Trigger properties.
This commit is contained in:
+11
-3
@@ -436,6 +436,7 @@ export enum ControlType {
|
|||||||
OnOffSwitch,
|
OnOffSwitch,
|
||||||
ABSwitch,
|
ABSwitch,
|
||||||
Select,
|
Select,
|
||||||
|
Trigger,
|
||||||
|
|
||||||
Tuner,
|
Tuner,
|
||||||
Vu,
|
Vu,
|
||||||
@@ -444,7 +445,7 @@ export enum ControlType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class UiControl implements Deserializable<UiControl> {
|
export class UiControl implements Deserializable<UiControl> {
|
||||||
deserialize(input: any): UiControl {
|
deserialize(input: any): UiControl {
|
||||||
this.symbol = input.symbol;
|
this.symbol = input.symbol;
|
||||||
this.name = input.name;
|
this.name = input.name;
|
||||||
this.index = input.index;
|
this.index = input.index;
|
||||||
@@ -458,7 +459,7 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
this.integer_property = input.integer_property;
|
this.integer_property = input.integer_property;
|
||||||
this.enumeration_property = input.enumeration_property;
|
this.enumeration_property = input.enumeration_property;
|
||||||
this.toggled_property = input.toggled_property;
|
this.toggled_property = input.toggled_property;
|
||||||
this.trigger = input.trigger;
|
this.trigger_property = input.trigger_property;
|
||||||
this.not_on_gui = input.not_on_gui;
|
this.not_on_gui = input.not_on_gui;
|
||||||
this.scale_points = ScalePoint.deserialize_array(input.scale_points);
|
this.scale_points = ScalePoint.deserialize_array(input.scale_points);
|
||||||
this.port_group = input.port_group;
|
this.port_group = input.port_group;
|
||||||
@@ -499,6 +500,10 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
this.controlType = ControlType.OnOffSwitch;
|
this.controlType = ControlType.OnOffSwitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.is_input && this.trigger_property)
|
||||||
|
{
|
||||||
|
this.controlType = ControlType.Trigger;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
applyProperties(properties: Partial<UiControl>): UiControl {
|
applyProperties(properties: Partial<UiControl>): UiControl {
|
||||||
@@ -546,7 +551,7 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
range_steps: number = 0;
|
range_steps: number = 0;
|
||||||
integer_property: boolean = false;
|
integer_property: boolean = false;
|
||||||
enumeration_property: boolean = false;
|
enumeration_property: boolean = false;
|
||||||
trigger: boolean = false;
|
trigger_property: boolean = false;
|
||||||
not_on_gui: boolean = false;
|
not_on_gui: boolean = false;
|
||||||
toggled_property: boolean = false;
|
toggled_property: boolean = false;
|
||||||
scale_points: ScalePoint[] = [];
|
scale_points: ScalePoint[] = [];
|
||||||
@@ -590,6 +595,9 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
isSelect(): boolean {
|
isSelect(): boolean {
|
||||||
return this.controlType === ControlType.Select;
|
return this.controlType === ControlType.Select;
|
||||||
}
|
}
|
||||||
|
isTrigger(): boolean {
|
||||||
|
return this.controlType === ControlType.Trigger;
|
||||||
|
}
|
||||||
isOutputSelect(): boolean {
|
isOutputSelect(): boolean {
|
||||||
return !this.is_input && this.controlType === ControlType.OutputSelect;
|
return !this.is_input && this.controlType === ControlType.OutputSelect;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ const MidiBindingView =
|
|||||||
isBinaryControl = (port.isAbToggle() || port.isOnOffSwitch());
|
isBinaryControl = (port.isAbToggle() || port.isOnOffSwitch());
|
||||||
if (midiBinding.bindingType !== MidiBinding.BINDING_TYPE_NONE) {
|
if (midiBinding.bindingType !== MidiBinding.BINDING_TYPE_NONE) {
|
||||||
canLatch = isBinaryControl;
|
canLatch = isBinaryControl;
|
||||||
canTrigger = port.trigger;
|
canTrigger = port.trigger_property;
|
||||||
showLinearControlTypeSelect = !(canLatch || canTrigger);
|
showLinearControlTypeSelect = !(canLatch || canTrigger);
|
||||||
showLinearRange = showLinearControlTypeSelect && midiBinding.linearControlType === MidiBinding.LINEAR_CONTROL_TYPE;
|
showLinearRange = showLinearControlTypeSelect && midiBinding.linearControlType === MidiBinding.LINEAR_CONTROL_TYPE;
|
||||||
canRotaryScale = showLinearControlTypeSelect && midiBinding.linearControlType === MidiBinding.CIRCULAR_CONTROL_TYPE;
|
canRotaryScale = showLinearControlTypeSelect && midiBinding.linearControlType === MidiBinding.CIRCULAR_CONTROL_TYPE;
|
||||||
|
|||||||
+127
-117
@@ -18,6 +18,7 @@
|
|||||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
import React, { TouchEvent, PointerEvent, ReactNode, Component, SyntheticEvent } from 'react';
|
import React, { TouchEvent, PointerEvent, ReactNode, Component, SyntheticEvent } from 'react';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
import { Theme } from '@mui/material/styles';
|
import { Theme } from '@mui/material/styles';
|
||||||
import { WithStyles } from '@mui/styles';
|
import { WithStyles } from '@mui/styles';
|
||||||
import createStyles from '@mui/styles/createStyles';
|
import createStyles from '@mui/styles/createStyles';
|
||||||
@@ -27,10 +28,11 @@ import Typography from '@mui/material/Typography';
|
|||||||
import Input from '@mui/material/Input';
|
import Input from '@mui/material/Input';
|
||||||
import Select from '@mui/material/Select';
|
import Select from '@mui/material/Select';
|
||||||
import Switch from '@mui/material/Switch';
|
import Switch from '@mui/material/Switch';
|
||||||
import Utility, {nullCast} from './Utility';
|
import Utility, { nullCast } from './Utility';
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
import {PiPedalModel,PiPedalModelFactory} from './PiPedalModel';
|
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
||||||
import {ReactComponent as DialIcon} from './svg/fx_dial.svg';
|
import { ReactComponent as DialIcon } from './svg/fx_dial.svg';
|
||||||
|
import { isDarkMode } from './DarkMode';
|
||||||
|
|
||||||
const MIN_ANGLE = -135;
|
const MIN_ANGLE = -135;
|
||||||
const MAX_ANGLE = 135;
|
const MAX_ANGLE = 135;
|
||||||
@@ -94,8 +96,7 @@ type PluginControlState = {
|
|||||||
|
|
||||||
const PluginControl =
|
const PluginControl =
|
||||||
withStyles(styles, { withTheme: true })(
|
withStyles(styles, { withTheme: true })(
|
||||||
class extends Component<PluginControlProps, PluginControlState>
|
class extends Component<PluginControlProps, PluginControlState> {
|
||||||
{
|
|
||||||
|
|
||||||
frameRef: React.RefObject<HTMLDivElement>;
|
frameRef: React.RefObject<HTMLDivElement>;
|
||||||
imgRef: React.RefObject<SVGSVGElement>;
|
imgRef: React.RefObject<SVGSVGElement>;
|
||||||
@@ -140,23 +141,18 @@ const PluginControl =
|
|||||||
return Utility.needsZoomedControls();
|
return Utility.needsZoomedControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
showZoomedControl()
|
showZoomedControl() {
|
||||||
{
|
if (this.props.uiControl && this.frameRef.current) {
|
||||||
if (this.props.uiControl && this.frameRef.current)
|
this.model.zoomUiControl(this.frameRef.current, this.props.instanceId, this.props.uiControl);
|
||||||
{
|
|
||||||
this.model.zoomUiControl(this.frameRef.current,this.props.instanceId,this.props.uiControl);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hideZoomedControl()
|
hideZoomedControl() {
|
||||||
{
|
if (this.frameRef.current && this.model.zoomedUiControl.get()?.source === this.frameRef.current) {
|
||||||
if (this.frameRef.current && this.model.zoomedUiControl.get()?.source === this.frameRef.current)
|
|
||||||
{
|
|
||||||
this.model.clearZoomedControl();
|
this.model.clearZoomedControl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount()
|
componentWillUnmount() {
|
||||||
{
|
|
||||||
this.hideZoomedControl();
|
this.hideZoomedControl();
|
||||||
}
|
}
|
||||||
inputChanged: boolean = false;
|
inputChanged: boolean = false;
|
||||||
@@ -172,12 +168,11 @@ const PluginControl =
|
|||||||
}
|
}
|
||||||
onInputFocus(event: SyntheticEvent): void {
|
onInputFocus(event: SyntheticEvent): void {
|
||||||
this.displayValueRef.current!.style.display = "none";
|
this.displayValueRef.current!.style.display = "none";
|
||||||
if (Utility.hasIMEKeyboard())
|
if (Utility.hasIMEKeyboard()) {
|
||||||
{
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.inputRef.current?.blur();
|
this.inputRef.current?.blur();
|
||||||
this.props.requestIMEEdit(nullCast(this.props.uiControl),this.props.value)
|
this.props.requestIMEEdit(nullCast(this.props.uiControl), this.props.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onInputKeyPress(e: any): void {
|
onInputKeyPress(e: any): void {
|
||||||
@@ -221,7 +216,7 @@ const PluginControl =
|
|||||||
// clamp and quantize.
|
// clamp and quantize.
|
||||||
let range = this.valueToRange(result);
|
let range = this.valueToRange(result);
|
||||||
result = this.rangeToValue(range);
|
result = this.rangeToValue(range);
|
||||||
let displayVal = this.props.uiControl?.formatShortValue(result)??"";
|
let displayVal = this.props.uiControl?.formatShortValue(result) ?? "";
|
||||||
if (event.currentTarget) {
|
if (event.currentTarget) {
|
||||||
event.currentTarget.value = displayVal;
|
event.currentTarget.value = displayVal;
|
||||||
}
|
}
|
||||||
@@ -270,11 +265,9 @@ const PluginControl =
|
|||||||
|
|
||||||
capturedPointers: number[] = [];
|
capturedPointers: number[] = [];
|
||||||
|
|
||||||
onBodyPointerDownCapture(e_: any): any
|
onBodyPointerDownCapture(e_: any): any {
|
||||||
{
|
|
||||||
let e = e_ as PointerEvent;
|
let e = e_ as PointerEvent;
|
||||||
if (this.isExtraTouch(e))
|
if (this.isExtraTouch(e)) {
|
||||||
{
|
|
||||||
this.isTap = false;
|
this.isTap = false;
|
||||||
this.captureElement!.setPointerCapture(e.pointerId);
|
this.captureElement!.setPointerCapture(e.pointerId);
|
||||||
this.capturedPointers.push(e.pointerId);
|
this.capturedPointers.push(e.pointerId);
|
||||||
@@ -305,10 +298,8 @@ const PluginControl =
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
if (this.isTouchDevice())
|
if (this.isTouchDevice()) {
|
||||||
{
|
if (this.props.uiControl?.isDial() ?? false) {
|
||||||
if (this.props.uiControl?.isDial()??false)
|
|
||||||
{
|
|
||||||
this.isTap = false;
|
this.isTap = false;
|
||||||
this.showZoomedControl();
|
this.showZoomedControl();
|
||||||
return;
|
return;
|
||||||
@@ -318,8 +309,7 @@ const PluginControl =
|
|||||||
++this.pointersDown;
|
++this.pointersDown;
|
||||||
|
|
||||||
this.mouseDown = true;
|
this.mouseDown = true;
|
||||||
if (this.pointersDown === 1)
|
if (this.pointersDown === 1) {
|
||||||
{
|
|
||||||
this.isTap = true;
|
this.isTap = true;
|
||||||
this.tapStartMs = Date.now();
|
this.tapStartMs = Date.now();
|
||||||
} else {
|
} else {
|
||||||
@@ -340,8 +330,8 @@ const PluginControl =
|
|||||||
this.captureElement = img;
|
this.captureElement = img;
|
||||||
document.body.addEventListener(
|
document.body.addEventListener(
|
||||||
"pointerdown",
|
"pointerdown",
|
||||||
this.onBodyPointerDownCapture,true
|
this.onBodyPointerDownCapture, true
|
||||||
);
|
);
|
||||||
|
|
||||||
img.setPointerCapture(e.pointerId);
|
img.setPointerCapture(e.pointerId);
|
||||||
if (img.style) {
|
if (img.style) {
|
||||||
@@ -350,11 +340,10 @@ const PluginControl =
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (this.isExtraTouch(e))
|
if (this.isExtraTouch(e)) {
|
||||||
{
|
|
||||||
++this.pointersDown;
|
++this.pointersDown;
|
||||||
this.isTap = false;
|
this.isTap = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,7 +356,7 @@ const PluginControl =
|
|||||||
if (this.isCapturedPointer(e)) {
|
if (this.isCapturedPointer(e)) {
|
||||||
--this.pointersDown;
|
--this.pointersDown;
|
||||||
this.isTap = false;
|
this.isTap = false;
|
||||||
|
|
||||||
|
|
||||||
this.releaseCapture(e);
|
this.releaseCapture(e);
|
||||||
}
|
}
|
||||||
@@ -378,21 +367,16 @@ const PluginControl =
|
|||||||
|
|
||||||
let ultraHigh = false;
|
let ultraHigh = false;
|
||||||
let high = false;
|
let high = false;
|
||||||
if (e.ctrlKey)
|
if (e.ctrlKey) {
|
||||||
{
|
|
||||||
ultraHigh = true;
|
ultraHigh = true;
|
||||||
}
|
}
|
||||||
if (e.shiftKey)
|
if (e.shiftKey) {
|
||||||
{
|
|
||||||
high = true;
|
high = true;
|
||||||
}
|
}
|
||||||
if (e.pointerType === "touch")
|
if (e.pointerType === "touch") {
|
||||||
{
|
if (this.pointersDown >= 3) {
|
||||||
if (this.pointersDown >= 3)
|
|
||||||
{
|
|
||||||
ultraHigh = true;
|
ultraHigh = true;
|
||||||
} else if (this.pointersDown === 2)
|
} else if (this.pointersDown === 2) {
|
||||||
{
|
|
||||||
high = true;
|
high = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,28 +395,24 @@ const PluginControl =
|
|||||||
}
|
}
|
||||||
private lastTapMs = 0;
|
private lastTapMs = 0;
|
||||||
|
|
||||||
resetToDefaultValue(uiControl: UiControl): void
|
resetToDefaultValue(uiControl: UiControl): void {
|
||||||
{
|
|
||||||
let value = uiControl.default_value;
|
let value = uiControl.default_value;
|
||||||
this.model.setPedalboardControl(this.props.instanceId,uiControl.symbol,value);
|
this.model.setPedalboardControl(this.props.instanceId, uiControl.symbol, value);
|
||||||
}
|
}
|
||||||
onPointerDoubleTap() {
|
onPointerDoubleTap() {
|
||||||
let uiControl = this.props.uiControl;
|
let uiControl = this.props.uiControl;
|
||||||
if (uiControl)
|
if (uiControl) {
|
||||||
{
|
if (uiControl.isDial()) {
|
||||||
if (uiControl.isDial())
|
|
||||||
{
|
|
||||||
this.resetToDefaultValue(uiControl);
|
this.resetToDefaultValue(uiControl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onPointerTap() {
|
onPointerTap() {
|
||||||
let tapTime = Date.now();
|
let tapTime = Date.now();
|
||||||
let dT = tapTime-this.lastTapMs;
|
let dT = tapTime - this.lastTapMs;
|
||||||
this.lastTapMs = tapTime;
|
this.lastTapMs = tapTime;
|
||||||
|
|
||||||
if (dT < 500)
|
if (dT < 500) {
|
||||||
{
|
|
||||||
this.onPointerDoubleTap();
|
this.onPointerDoubleTap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,32 +422,29 @@ const PluginControl =
|
|||||||
|
|
||||||
if (this.isCapturedPointer(e)) {
|
if (this.isCapturedPointer(e)) {
|
||||||
--this.pointersDown;
|
--this.pointersDown;
|
||||||
|
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let dRange = this.updateRange(e)
|
let dRange = this.updateRange(e)
|
||||||
this.previewRange(dRange, true);
|
this.previewRange(dRange, true);
|
||||||
|
|
||||||
this.releaseCapture(e);
|
this.releaseCapture(e);
|
||||||
if (this.isTap)
|
if (this.isTap) {
|
||||||
{
|
let ms = Date.now() - this.tapStartMs;
|
||||||
let ms = Date.now()-this.tapStartMs;
|
if (ms < 200) {
|
||||||
if (ms < 200)
|
|
||||||
{
|
|
||||||
this.onPointerTap();
|
this.onPointerTap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
--this.pointersDown;
|
--this.pointersDown;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseCapture(e: PointerEvent<SVGSVGElement>)
|
releaseCapture(e: PointerEvent<SVGSVGElement>) {
|
||||||
{
|
|
||||||
let img = this.imgRef.current;
|
let img = this.imgRef.current;
|
||||||
|
|
||||||
if (img && img.style) {
|
if (img && img.style) {
|
||||||
img.releasePointerCapture(e.pointerId);
|
img.releasePointerCapture(e.pointerId);
|
||||||
img.style.opacity = "" + DEFAULT_OPACITY;
|
img.style.opacity = "" + DEFAULT_OPACITY;
|
||||||
@@ -480,14 +457,14 @@ const PluginControl =
|
|||||||
}
|
}
|
||||||
document.body.removeEventListener(
|
document.body.removeEventListener(
|
||||||
"pointerdown",
|
"pointerdown",
|
||||||
this.onBodyPointerDownCapture,true
|
this.onBodyPointerDownCapture, true
|
||||||
);
|
);
|
||||||
|
|
||||||
this.mouseDown = false;
|
this.mouseDown = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clickSlop() {
|
clickSlop() {
|
||||||
return 3.5; // maybe larger on touch devices.
|
return 3.5; // maybe larger on touch devices.
|
||||||
}
|
}
|
||||||
onPointerMove(e: PointerEvent<SVGSVGElement>): void {
|
onPointerMove(e: PointerEvent<SVGSVGElement>): void {
|
||||||
@@ -499,15 +476,27 @@ const PluginControl =
|
|||||||
let x = e.clientX;
|
let x = e.clientX;
|
||||||
let y = e.clientY;
|
let y = e.clientY;
|
||||||
let dx = x - this.startX;
|
let dx = x - this.startX;
|
||||||
let dy = y-this.startY;
|
let dy = y - this.startY;
|
||||||
let distance = Math.sqrt(dx*dx+dy*dy);
|
let distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
if (distance >= this.clickSlop())
|
if (distance >= this.clickSlop()) {
|
||||||
{
|
|
||||||
this.isTap = false;
|
this.isTap = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
handleTriggerMouseDown() {
|
||||||
|
let uiControl = this.props.uiControl;
|
||||||
|
if (uiControl)
|
||||||
|
{
|
||||||
|
this.model.setPedalboardControl(this.props.instanceId,uiControl.symbol,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleTriggerMouseUp() {
|
||||||
|
let uiControl = this.props.uiControl;
|
||||||
|
if (uiControl)
|
||||||
|
{
|
||||||
|
this.model.setPedalboardControl(this.props.instanceId,uiControl.symbol,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
previewInputValue(value: number, commitValue: boolean) {
|
previewInputValue(value: number, commitValue: boolean) {
|
||||||
let range = this.valueToRange(value);
|
let range = this.valueToRange(value);
|
||||||
value = this.rangeToValue(range);
|
value = this.rangeToValue(range);
|
||||||
@@ -547,13 +536,12 @@ const PluginControl =
|
|||||||
}
|
}
|
||||||
let inputElement = this.inputRef.current;
|
let inputElement = this.inputRef.current;
|
||||||
if (inputElement) {
|
if (inputElement) {
|
||||||
let v = this.props.uiControl?.formatShortValue(value)??"";
|
let v = this.props.uiControl?.formatShortValue(value) ?? "";
|
||||||
inputElement.value = v;
|
inputElement.value = v;
|
||||||
}
|
}
|
||||||
let displayValue = this.displayValueRef.current;
|
let displayValue = this.displayValueRef.current;
|
||||||
if (displayValue)
|
if (displayValue) {
|
||||||
{
|
let v = this.formatDisplayValue(this.props.uiControl, value);
|
||||||
let v = this.formatDisplayValue(this.props.uiControl,value);
|
|
||||||
displayValue.childNodes[0].textContent = v;
|
displayValue.childNodes[0].textContent = v;
|
||||||
}
|
}
|
||||||
let selectElement = this.selectRef.current;
|
let selectElement = this.selectRef.current;
|
||||||
@@ -577,9 +565,9 @@ const PluginControl =
|
|||||||
}
|
}
|
||||||
onSelectChanged(e: any, value: any) {
|
onSelectChanged(e: any, value: any) {
|
||||||
let target = e.target;
|
let target = e.target;
|
||||||
setTimeout(()=> {
|
setTimeout(() => {
|
||||||
this.props.onChange(target.value);
|
this.props.onChange(target.value);
|
||||||
},0);
|
}, 0);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -610,7 +598,7 @@ const PluginControl =
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Select variant="standard"
|
<Select variant="standard"
|
||||||
ref={this.selectRef}
|
ref={this.selectRef}
|
||||||
value={control.clampSelectValue(value)}
|
value={control.clampSelectValue(value)}
|
||||||
onChange={this.onSelectChanged}
|
onChange={this.onSelectChanged}
|
||||||
@@ -619,7 +607,7 @@ const PluginControl =
|
|||||||
id: 'id' + control.symbol,
|
id: 'id' + control.symbol,
|
||||||
style: { fontSize: FONT_SIZE }
|
style: { fontSize: FONT_SIZE }
|
||||||
}}
|
}}
|
||||||
style={{ marginLeft: 4, marginRight: 4, width: 140,fontSize: 14 }}
|
style={{ marginLeft: 4, marginRight: 4, width: 140, fontSize: 14 }}
|
||||||
>
|
>
|
||||||
{control.scale_points.map((scale_point: ScalePoint) => (
|
{control.scale_points.map((scale_point: ScalePoint) => (
|
||||||
<MenuItem key={scale_point.value} value={scale_point.value}>{scale_point.label}</MenuItem>
|
<MenuItem key={scale_point.value} value={scale_point.value}>{scale_point.label}</MenuItem>
|
||||||
@@ -645,11 +633,10 @@ const PluginControl =
|
|||||||
value = Math.round(value);
|
value = Math.round(value);
|
||||||
}
|
}
|
||||||
let range: number;
|
let range: number;
|
||||||
if (uiControl.is_logarithmic)
|
if (uiControl.is_logarithmic) {
|
||||||
{
|
range = Math.log(value / uiControl.min_value) / Math.log(uiControl.max_value / uiControl.min_value);
|
||||||
range = Math.log(value/uiControl.min_value)/Math.log(uiControl.max_value/uiControl.min_value);
|
if (uiControl.range_steps > 1) {
|
||||||
if (uiControl.range_steps > 1) {
|
range = Math.round(range * (uiControl.range_steps - 1)) / (uiControl.range_steps - 1);
|
||||||
range = Math.round(range*(uiControl.range_steps-1))/(uiControl.range_steps-1);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
range = (value - uiControl.min_value) / (uiControl.max_value - uiControl.min_value);
|
range = (value - uiControl.min_value) / (uiControl.max_value - uiControl.min_value);
|
||||||
@@ -666,17 +653,14 @@ const PluginControl =
|
|||||||
let uiControl = this.props.uiControl;
|
let uiControl = this.props.uiControl;
|
||||||
if (uiControl) {
|
if (uiControl) {
|
||||||
if (uiControl.range_steps > 1) {
|
if (uiControl.range_steps > 1) {
|
||||||
range = Math.round(range * (uiControl.range_steps-1)) / (uiControl.range_steps-1);
|
range = Math.round(range * (uiControl.range_steps - 1)) / (uiControl.range_steps - 1);
|
||||||
}
|
}
|
||||||
let value: number;
|
let value: number;
|
||||||
if (uiControl.min_value === uiControl.max_value)
|
if (uiControl.min_value === uiControl.max_value) {
|
||||||
{
|
|
||||||
value = uiControl.min_value;
|
value = uiControl.min_value;
|
||||||
} else
|
} else {
|
||||||
{
|
if (uiControl.is_logarithmic) {
|
||||||
if (uiControl.is_logarithmic)
|
value = uiControl.min_value * Math.pow(uiControl.max_value / uiControl.min_value, range);
|
||||||
{
|
|
||||||
value = uiControl.min_value*Math.pow(uiControl.max_value/uiControl.min_value,range);
|
|
||||||
} else {
|
} else {
|
||||||
value = range * (uiControl.max_value - uiControl.min_value) + uiControl.min_value;
|
value = range * (uiControl.max_value - uiControl.min_value) + uiControl.min_value;
|
||||||
}
|
}
|
||||||
@@ -724,45 +708,71 @@ const PluginControl =
|
|||||||
let isSelect = control.isSelect();
|
let isSelect = control.isSelect();
|
||||||
let isAbSwitch = control.isAbToggle();
|
let isAbSwitch = control.isAbToggle();
|
||||||
let isOnOffSwitch = control.isOnOffSwitch();
|
let isOnOffSwitch = control.isOnOffSwitch();
|
||||||
|
let isTrigger = control.isTrigger();
|
||||||
|
|
||||||
if (isAbSwitch) {
|
if (isAbSwitch) {
|
||||||
switchText = control.scale_points[0].value === value ? control.scale_points[0].label : control.scale_points[1].label;
|
switchText = control.scale_points[0].value === value ? control.scale_points[0].label : control.scale_points[1].label;
|
||||||
}
|
}
|
||||||
|
|
||||||
let item_width = isSelect ? 160 : 80;
|
let item_width: number | undefined = isSelect ? 160 : 80;
|
||||||
|
if (isTrigger)
|
||||||
|
{
|
||||||
|
item_width = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={this.frameRef} style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", width: item_width, margin: 8 }}>
|
<div ref={this.frameRef} style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", width: item_width, margin: 8 }}>
|
||||||
{/* TITLE SECTION */}
|
{/* TITLE SECTION */}
|
||||||
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8,marginLeft: isSelect? 16: 0, marginRight: 0 }}>
|
<div style={{ flex: "0 0 auto", alignSelf:"stretch", marginBottom: 8, marginLeft: isSelect ? 16 : 0, marginRight: 0 }}>
|
||||||
<Typography variant="caption" display="block" noWrap style={{
|
<Typography variant="caption" display="block" noWrap style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: isSelect ? "left" : "center"
|
textAlign: isSelect ? "left" : "center"
|
||||||
}}> {control.name}</Typography>
|
}}> {isTrigger ? "\u00A0" : control.name}</Typography>
|
||||||
</div>
|
</div>
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
<div style={{ flex: "0 0 auto" }}>
|
<div style={{ flex: "0 0 auto" }}>
|
||||||
{(isSelect || isAbSwitch || isOnOffSwitch) ? (
|
{isTrigger ? (
|
||||||
this.makeSelect(control, value)
|
<Button variant="contained" color="primary" size="small"
|
||||||
) : (
|
onMouseDown={
|
||||||
<div style={{ flex: "0 1 auto" }}>
|
(evt)=> { this.handleTriggerMouseDown(); }
|
||||||
<DialIcon ref={this.imgRef}
|
}
|
||||||
style={{ overscrollBehavior: "none", touchAction: "none", fill: dialColor,
|
onMouseUp={
|
||||||
width: 36, height: 36, opacity: DEFAULT_OPACITY, transform: this.getRotationTransform() }}
|
(evt)=> { this.handleTriggerMouseUp(); }
|
||||||
onTouchStart={this.onTouchStart} onTouchMove={this.onTouchMove}
|
}
|
||||||
onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} onPointerMoveCapture={this.onPointerMove} onDrag={this.onDrag}
|
style={{
|
||||||
|
textTransform: "none",
|
||||||
/>
|
background: (isDarkMode() ? "#6750A4" : undefined),
|
||||||
</div>
|
marginLeft: 8, marginRight: 8,minWidth:60
|
||||||
|
}}
|
||||||
|
|
||||||
|
>
|
||||||
|
{control.name}
|
||||||
|
</Button>
|
||||||
)
|
)
|
||||||
|
: ((isSelect || isAbSwitch || isOnOffSwitch) ? (
|
||||||
|
this.makeSelect(control, value)
|
||||||
|
) : (
|
||||||
|
<div style={{ flex: "0 1 auto" }}>
|
||||||
|
<DialIcon ref={this.imgRef}
|
||||||
|
style={{
|
||||||
|
overscrollBehavior: "none", touchAction: "none", fill: dialColor,
|
||||||
|
width: 36, height: 36, opacity: DEFAULT_OPACITY, transform: this.getRotationTransform()
|
||||||
|
}}
|
||||||
|
onTouchStart={this.onTouchStart} onTouchMove={this.onTouchMove}
|
||||||
|
onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} onPointerMoveCapture={this.onPointerMove} onDrag={this.onDrag}
|
||||||
|
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* LABEL/EDIT SECTION*/}
|
{/* LABEL/EDIT SECTION*/}
|
||||||
<div style={{ flex: "0 0 auto", position: "relative", width: 60 }}>
|
<div style={{ flex: "0 0 auto", position: "relative", width: 60 }}>
|
||||||
{(!(isSelect || isOnOffSwitch)) &&
|
{(!(isSelect || isOnOffSwitch || isTrigger)) &&
|
||||||
(
|
(
|
||||||
(isAbSwitch) ? (
|
(isAbSwitch) ? (
|
||||||
<Typography variant="caption" display="block" noWrap style={{
|
<Typography variant="caption" display="block" noWrap style={{
|
||||||
@@ -770,7 +780,7 @@ const PluginControl =
|
|||||||
}}> {switchText} </Typography>
|
}}> {switchText} </Typography>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<Input key={value}
|
<Input key={value}
|
||||||
type="number"
|
type="number"
|
||||||
defaultValue={control.formatShortValue(value)}
|
defaultValue={control.formatShortValue(value)}
|
||||||
error={this.state.error}
|
error={this.state.error}
|
||||||
@@ -785,10 +795,10 @@ const PluginControl =
|
|||||||
|
|
||||||
onKeyPress={this.onInputKeyPress} />
|
onKeyPress={this.onInputKeyPress} />
|
||||||
<div className={classes.displayValue} ref={this.displayValueRef} onClick={(e) => { this.inputRef.current!.focus(); }} >
|
<div className={classes.displayValue} ref={this.displayValueRef} onClick={(e) => { this.inputRef.current!.focus(); }} >
|
||||||
<Typography noWrap color="inherit" style={{ fontSize: "12.8px", paddingTop:4, paddingBottom: 6 }}
|
<Typography noWrap color="inherit" style={{ fontSize: "12.8px", paddingTop: 4, paddingBottom: 6 }}
|
||||||
|
|
||||||
>
|
>
|
||||||
{this.formatDisplayValue(control, value)}</Typography>
|
{this.formatDisplayValue(control, value)}</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export const SplitTypeControl: UiControl = new UiControl().deserialize({
|
|||||||
enumeration_property: true,
|
enumeration_property: true,
|
||||||
not_on_gui: false,
|
not_on_gui: false,
|
||||||
toggled_property: false,
|
toggled_property: false,
|
||||||
|
trigger_property: false,
|
||||||
scale_points: ScalePoint.deserialize_array(
|
scale_points: ScalePoint.deserialize_array(
|
||||||
[
|
[
|
||||||
{ value: 0, label: "A/B" },
|
{ value: 0, label: "A/B" },
|
||||||
@@ -60,6 +61,7 @@ export const SplitAbControl: UiControl = new UiControl().deserialize({
|
|||||||
enumeration_property: true,
|
enumeration_property: true,
|
||||||
not_on_gui: false,
|
not_on_gui: false,
|
||||||
toggled_property: false,
|
toggled_property: false,
|
||||||
|
trigger_property: false,
|
||||||
scale_points: ScalePoint.deserialize_array(
|
scale_points: ScalePoint.deserialize_array(
|
||||||
[
|
[
|
||||||
{ value: 0, label: "A" },
|
{ value: 0, label: "A" },
|
||||||
@@ -83,6 +85,8 @@ export const SplitMixControl: UiControl = new UiControl().deserialize({
|
|||||||
enumeration_property: false,
|
enumeration_property: false,
|
||||||
not_on_gui: false,
|
not_on_gui: false,
|
||||||
toggled_property: false,
|
toggled_property: false,
|
||||||
|
trigger_property: false,
|
||||||
|
|
||||||
scale_points: []
|
scale_points: []
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -100,6 +104,8 @@ export const SplitPanLeftControl: UiControl = new UiControl().deserialize({
|
|||||||
enumeration_property: false,
|
enumeration_property: false,
|
||||||
not_on_gui: false,
|
not_on_gui: false,
|
||||||
toggled_property: false,
|
toggled_property: false,
|
||||||
|
trigger_property: false,
|
||||||
|
|
||||||
scale_points: []
|
scale_points: []
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -117,6 +123,8 @@ export const SplitVolLeftControl: UiControl = new UiControl().deserialize({
|
|||||||
enumeration_property: false,
|
enumeration_property: false,
|
||||||
not_on_gui: false,
|
not_on_gui: false,
|
||||||
toggled_property: false,
|
toggled_property: false,
|
||||||
|
trigger_property: false,
|
||||||
|
|
||||||
units: Units.db,
|
units: Units.db,
|
||||||
scale_points: [
|
scale_points: [
|
||||||
new ScalePoint().deserialize({
|
new ScalePoint().deserialize({
|
||||||
@@ -141,6 +149,8 @@ export const SplitPanRightControl: UiControl = new UiControl().deserialize({
|
|||||||
enumeration_property: false,
|
enumeration_property: false,
|
||||||
not_on_gui: false,
|
not_on_gui: false,
|
||||||
toggled_property: false,
|
toggled_property: false,
|
||||||
|
trigger_property: false,
|
||||||
|
|
||||||
scale_points: []
|
scale_points: []
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -158,6 +168,8 @@ export const SplitVolRightControl: UiControl = new UiControl().deserialize({
|
|||||||
enumeration_property: false,
|
enumeration_property: false,
|
||||||
not_on_gui: false,
|
not_on_gui: false,
|
||||||
toggled_property: false,
|
toggled_property: false,
|
||||||
|
trigger_property: false,
|
||||||
|
|
||||||
units: Units.db,
|
units: Units.db,
|
||||||
scale_points: [
|
scale_points: [
|
||||||
new ScalePoint().deserialize({
|
new ScalePoint().deserialize({
|
||||||
|
|||||||
+4
-1
@@ -118,6 +118,7 @@ void PluginHost::LilvUris::Initialize(LilvWorld *pWorld)
|
|||||||
core__toggled = lilv_new_uri(pWorld, LV2_CORE__toggled);
|
core__toggled = lilv_new_uri(pWorld, LV2_CORE__toggled);
|
||||||
core__connectionOptional = lilv_new_uri(pWorld, LV2_CORE__connectionOptional);
|
core__connectionOptional = lilv_new_uri(pWorld, LV2_CORE__connectionOptional);
|
||||||
portprops__not_on_gui_property_uri = lilv_new_uri(pWorld, LV2_PORT_PROPS__notOnGUI);
|
portprops__not_on_gui_property_uri = lilv_new_uri(pWorld, LV2_PORT_PROPS__notOnGUI);
|
||||||
|
portprops__trigger = lilv_new_uri(pWorld,LV2_PORT_PROPS__trigger);
|
||||||
midi__event = lilv_new_uri(pWorld, LV2_MIDI__MidiEvent);
|
midi__event = lilv_new_uri(pWorld, LV2_MIDI__MidiEvent);
|
||||||
core__designation = lilv_new_uri(pWorld, LV2_CORE__designation);
|
core__designation = lilv_new_uri(pWorld, LV2_CORE__designation);
|
||||||
portgroups__group = lilv_new_uri(pWorld, LV2_PORT_GROUPS__group);
|
portgroups__group = lilv_new_uri(pWorld, LV2_PORT_GROUPS__group);
|
||||||
@@ -932,6 +933,7 @@ Lv2PortInfo::Lv2PortInfo(PluginHost *host, const LilvPlugin *plugin, const LilvP
|
|||||||
this->toggled_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris->core__toggled);
|
this->toggled_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris->core__toggled);
|
||||||
this->not_on_gui_ = lilv_port_has_property(plugin, pPort, host->lilvUris->portprops__not_on_gui_property_uri);
|
this->not_on_gui_ = lilv_port_has_property(plugin, pPort, host->lilvUris->portprops__not_on_gui_property_uri);
|
||||||
this->connection_optional_ = lilv_port_has_property(plugin, pPort, host->lilvUris->core__connectionOptional);
|
this->connection_optional_ = lilv_port_has_property(plugin, pPort, host->lilvUris->core__connectionOptional);
|
||||||
|
this->trigger_property_ = lilv_port_has_property(plugin,pPort,host->lilvUris->portprops__trigger);
|
||||||
|
|
||||||
LilvScalePoints *pScalePoints = lilv_port_get_scale_points(plugin, pPort);
|
LilvScalePoints *pScalePoints = lilv_port_get_scale_points(plugin, pPort);
|
||||||
LILV_FOREACH(scale_points, iSP, pScalePoints)
|
LILV_FOREACH(scale_points, iSP, pScalePoints)
|
||||||
@@ -1593,7 +1595,7 @@ json_map::storage_type<Lv2PortInfo> Lv2PortInfo::jmap{
|
|||||||
MAP_REF(Lv2PortInfo, is_logarithmic),
|
MAP_REF(Lv2PortInfo, is_logarithmic),
|
||||||
MAP_REF(Lv2PortInfo, display_priority),
|
MAP_REF(Lv2PortInfo, display_priority),
|
||||||
MAP_REF(Lv2PortInfo, range_steps),
|
MAP_REF(Lv2PortInfo, range_steps),
|
||||||
MAP_REF(Lv2PortInfo, trigger),
|
MAP_REF(Lv2PortInfo, trigger_property),
|
||||||
MAP_REF(Lv2PortInfo, integer_property),
|
MAP_REF(Lv2PortInfo, integer_property),
|
||||||
MAP_REF(Lv2PortInfo, enumeration_property),
|
MAP_REF(Lv2PortInfo, enumeration_property),
|
||||||
MAP_REF(Lv2PortInfo, toggled_property),
|
MAP_REF(Lv2PortInfo, toggled_property),
|
||||||
@@ -1662,6 +1664,7 @@ json_map::storage_type<Lv2PluginUiPort> Lv2PluginUiPort::jmap{{
|
|||||||
MAP_REF(Lv2PluginUiPort, enumeration_property),
|
MAP_REF(Lv2PluginUiPort, enumeration_property),
|
||||||
MAP_REF(Lv2PluginUiPort, not_on_gui),
|
MAP_REF(Lv2PluginUiPort, not_on_gui),
|
||||||
MAP_REF(Lv2PluginUiPort, toggled_property),
|
MAP_REF(Lv2PluginUiPort, toggled_property),
|
||||||
|
MAP_REF(Lv2PluginUiPort, trigger_property),
|
||||||
MAP_REF(Lv2PluginUiPort, scale_points),
|
MAP_REF(Lv2PluginUiPort, scale_points),
|
||||||
MAP_REF(Lv2PluginUiPort, port_group),
|
MAP_REF(Lv2PluginUiPort, port_group),
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -214,7 +214,7 @@ namespace pipedal
|
|||||||
bool is_logarithmic_ = false;
|
bool is_logarithmic_ = false;
|
||||||
int display_priority_ = -1;
|
int display_priority_ = -1;
|
||||||
int range_steps_ = 0;
|
int range_steps_ = 0;
|
||||||
bool trigger_ = false;
|
bool trigger_property_ = false;
|
||||||
bool integer_property_ = false;
|
bool integer_property_ = false;
|
||||||
bool enumeration_property_ = false;
|
bool enumeration_property_ = false;
|
||||||
bool toggled_property_ = false;
|
bool toggled_property_ = false;
|
||||||
@@ -285,7 +285,7 @@ namespace pipedal
|
|||||||
LV2_PROPERTY_GETSET_SCALAR(is_logarithmic);
|
LV2_PROPERTY_GETSET_SCALAR(is_logarithmic);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(display_priority);
|
LV2_PROPERTY_GETSET_SCALAR(display_priority);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(range_steps);
|
LV2_PROPERTY_GETSET_SCALAR(range_steps);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(trigger);
|
LV2_PROPERTY_GETSET_SCALAR(trigger_property);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(integer_property);
|
LV2_PROPERTY_GETSET_SCALAR(integer_property);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(enumeration_property);
|
LV2_PROPERTY_GETSET_SCALAR(enumeration_property);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(toggled_property);
|
LV2_PROPERTY_GETSET_SCALAR(toggled_property);
|
||||||
@@ -496,6 +496,7 @@ namespace pipedal
|
|||||||
default_value_(pPort->default_value()), range_steps_(pPort->range_steps()), display_priority_(pPort->display_priority()),
|
default_value_(pPort->default_value()), range_steps_(pPort->range_steps()), display_priority_(pPort->display_priority()),
|
||||||
is_logarithmic_(pPort->is_logarithmic()), integer_property_(pPort->integer_property()), enumeration_property_(pPort->enumeration_property()),
|
is_logarithmic_(pPort->is_logarithmic()), integer_property_(pPort->integer_property()), enumeration_property_(pPort->enumeration_property()),
|
||||||
toggled_property_(pPort->toggled_property()), not_on_gui_(pPort->not_on_gui()), scale_points_(pPort->scale_points()),
|
toggled_property_(pPort->toggled_property()), not_on_gui_(pPort->not_on_gui()), scale_points_(pPort->scale_points()),
|
||||||
|
trigger_property_(pPort->trigger_property()),
|
||||||
comment_(pPort->comment()), units_(pPort->units()),
|
comment_(pPort->comment()), units_(pPort->units()),
|
||||||
connection_optional_(pPort->connection_optional())
|
connection_optional_(pPort->connection_optional())
|
||||||
{
|
{
|
||||||
@@ -536,6 +537,7 @@ namespace pipedal
|
|||||||
bool enumeration_property_ = false;
|
bool enumeration_property_ = false;
|
||||||
bool not_on_gui_ = false;
|
bool not_on_gui_ = false;
|
||||||
bool toggled_property_ = false;
|
bool toggled_property_ = false;
|
||||||
|
bool trigger_property_ = false;
|
||||||
std::vector<Lv2ScalePoint> scale_points_;
|
std::vector<Lv2ScalePoint> scale_points_;
|
||||||
std::string port_group_;
|
std::string port_group_;
|
||||||
|
|
||||||
@@ -561,6 +563,7 @@ namespace pipedal
|
|||||||
LV2_PROPERTY_GETSET_SCALAR(integer_property);
|
LV2_PROPERTY_GETSET_SCALAR(integer_property);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(enumeration_property);
|
LV2_PROPERTY_GETSET_SCALAR(enumeration_property);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(toggled_property);
|
LV2_PROPERTY_GETSET_SCALAR(toggled_property);
|
||||||
|
LV2_PROPERTY_GETSET_SCALAR(trigger_property);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(not_on_gui);
|
LV2_PROPERTY_GETSET_SCALAR(not_on_gui);
|
||||||
LV2_PROPERTY_GETSET(scale_points);
|
LV2_PROPERTY_GETSET(scale_points);
|
||||||
LV2_PROPERTY_GETSET(units);
|
LV2_PROPERTY_GETSET(units);
|
||||||
@@ -664,6 +667,7 @@ namespace pipedal
|
|||||||
AutoLilvNode core__toggled;
|
AutoLilvNode core__toggled;
|
||||||
AutoLilvNode core__connectionOptional;
|
AutoLilvNode core__connectionOptional;
|
||||||
AutoLilvNode portprops__not_on_gui_property_uri;
|
AutoLilvNode portprops__not_on_gui_property_uri;
|
||||||
|
AutoLilvNode portprops__trigger;
|
||||||
AutoLilvNode midi__event;
|
AutoLilvNode midi__event;
|
||||||
AutoLilvNode core__designation;
|
AutoLilvNode core__designation;
|
||||||
AutoLilvNode portgroups__group;
|
AutoLilvNode portgroups__group;
|
||||||
|
|||||||
Reference in New Issue
Block a user