Editor/ChitChat/ActionWidgets/SpeakActionInspectorWidget.cs
using Sandbox;
using Editor;
namespace ChitChat.Editor;
public class SpeakActionInspectorWidget : Widget
{
private SerializedObject _serializedObject;
private readonly Layout _content;
public SpeakActionInspectorWidget(SerializedObject speakActionSO, Widget parent) : base(parent)
{
Name = "SpeakAction";
SetSerializedObject(speakActionSO);
Layout = Layout.Column();
_content = Layout;
Rebuild();
}
public void SetSerializedObject(SerializedObject speakActionSO)
{
if (!speakActionSO.TypeName.Equals(nameof(SpeakAction)))
{
Log.Error("SerializedObject is not a " + nameof(SpeakAction) + "!");
return;
}
_serializedObject = speakActionSO;
}
public void Rebuild()
{
_content.Clear(true);
_content.Add(new TextSeperatorWidget("Character", 65, this));
SpeakActionCharacterSettingsWidget characterSettings = new SpeakActionCharacterSettingsWidget(_serializedObject, this);
_content.Add(characterSettings);
_content.Add(new TextSeperatorWidget("Dialogue Text", 85, this));
SpeakActionTextControlWidget textWidget = new SpeakActionTextControlWidget(_serializedObject.GetProperty(nameof(SpeakAction.Text)));
textWidget.FixedHeight = 200;
_content.Add(textWidget);
_content.Add(new TextSeperatorWidget("Settings", 55, this));
//Input settings
SpeakActionInputSettingsWidget inputSettings = new SpeakActionInputSettingsWidget(_serializedObject, this);
_content.Add(inputSettings);
_content.AddSeparator(2, Color.Transparent);
//Write settings
SpeakActionWriteSettingsWidget writeSettings = new SpeakActionWriteSettingsWidget(_serializedObject, this);
_content.Add(writeSettings);
_content.Add(new TextSeperatorWidget("Audio", 45, this));
//Sound Settings
SpeakActionAudioSettingsWidget audioSettings = new SpeakActionAudioSettingsWidget(_serializedObject, this);
_content.Add(audioSettings);
}
private sealed class SpeakActionCharacterSettingsWidget : Widget
{
private CharacterPictureDropdown _pictureDropdown;
private Label _characterNameLabel;
private TextureWidget _characterPicturePreview;
private DialogueCharacter _character;
private SerializedObject _serializedObject;
private Widget _characterPictureSettings;
/// <summary>
/// Property is assumed to be DialogueData.
/// </summary>
public SpeakActionCharacterSettingsWidget(SerializedObject so, Widget parent) : base(parent)
{
_serializedObject = so;
SerializedProperty character = _serializedObject.GetProperty(nameof(SpeakAction.Character));
_character = character.GetValue<DialogueCharacter>();
Layout = Layout.Row();
Layout.Alignment = TextFlag.LeftTop;
VerticalSizeMode = SizeMode.CanShrink;
//Character Preview
Widget characterPreviewContainer = new Widget(this);
characterPreviewContainer.MaximumWidth = 300;
characterPreviewContainer.Layout = Layout.Column();
characterPreviewContainer.Layout.Alignment = TextFlag.LeftTop;
Layout.Add(characterPreviewContainer);
int first = _serializedObject.GetProperty(nameof(SpeakAction.CharacterIndex)).GetValue<int>();
_characterPicturePreview = new TextureWidget()
{
Parent = this,
FixedSize = new Vector2(300, 300),
RetainAspectRatio = true,
Visible = _character.IsValid()
};
if (_character.IsValid() && _character.CharacterPictures?.Count > 0 && first < _character.CharacterPictures.Count)
{
if (first < 0)
first = 0;
_characterPicturePreview.Texture = _character.CharacterPictures[first].Picture;
}
else
_characterPicturePreview.Texture = null;
characterPreviewContainer.Layout.Add(_characterPicturePreview);
ControlWidget characterControlWidget = ControlWidget.Create(_serializedObject.GetProperty(nameof(SpeakAction.Character)));
characterControlWidget.MaximumWidth = 300;
characterControlWidget.MaximumHeight = 30;
characterPreviewContainer.Layout.AddSeparator(2, Color.Transparent);
characterPreviewContainer.Layout.Add(characterControlWidget);
//Character Info
_characterPictureSettings = new Widget(this);
_characterPictureSettings.Layout = Layout.Column();
_characterPictureSettings.Layout.Margin = new Sandbox.UI.Margin(5, 0, 0, 0);
_characterPictureSettings.Layout.Alignment = TextFlag.LeftTop;
_characterPictureSettings.Visible = (_character.IsValid());
Layout.Add(_characterPictureSettings);
_characterNameLabel = new Label(_character.IsValid() ? _character.Name : string.Empty, this);
_characterNameLabel.SetStyles("font-size: 23px;");
_characterNameLabel.MinimumHeight = 30;
_characterNameLabel.ToolTip = "";
_characterPictureSettings.Layout.Add(_characterNameLabel);
_characterPictureSettings.Layout.AddSeparator(2, Color.Transparent);
Label picDropdownLabel = new Label("Picture")
{
ContentMargins = new Sandbox.UI.Margin(2, 0, 0, 0),
};
_pictureDropdown = new CharacterPictureDropdown(character, first, this);
_pictureDropdown.onItemSelected += OnItemSelected;
_pictureDropdown.MinimumHeight = 30;
_pictureDropdown.MinimumWidth = 300;
_characterPictureSettings.Layout.Add(picDropdownLabel);
_characterPictureSettings.Layout.Add(_pictureDropdown);
_characterPictureSettings.Layout.AddSeparator(2, Color.Transparent);
Label picPosLabel = new Label("Picture Position")
{
ContentMargins = new Sandbox.UI.Margin(2, 0, 0, 0),
};
EnumControlWidget picturePosWidget = new EnumControlWidget(_serializedObject.GetProperty(nameof(SpeakAction.PicturePosition)));
picturePosWidget.MaximumWidth = 300;
_characterPictureSettings.Layout.Add(picPosLabel);
_characterPictureSettings.Layout.Add(picturePosWidget);
_serializedObject.OnPropertyChanged += OnPropertyChanged;
}
public override void OnDestroyed()
{
_serializedObject.OnPropertyChanged -= OnPropertyChanged;
_pictureDropdown.onItemSelected -= OnItemSelected;
}
public void UpdateUI()
{
int first = _serializedObject.GetProperty(nameof(SpeakAction.CharacterIndex)).GetValue<int>();
SerializedProperty characterProp = _serializedObject.GetProperty(nameof(SpeakAction.Character));
_character = characterProp.GetValue<DialogueCharacter>();
if (_character.IsValid())
{
if (first > _character.CharacterPictures?.Count - 1 || first < 0)
{
_serializedObject.GetProperty(nameof(SpeakAction.CharacterIndex)).SetValue<int>(0);
first = 0;
}
}
//Update name label
if (_character.IsValid())
_characterNameLabel.Text = _character?.Name;
else
_characterNameLabel.Text = string.Empty;
//Update picture dropdown
if (_character.IsValid())
_pictureDropdown.UpdateProperty(characterProp, first);
_characterPictureSettings.Visible = (_character != null);
//Update preview texture
if (_character.IsValid() && _character.CharacterPictures?.Count > 0 && first < _character.CharacterPictures.Count)
_characterPicturePreview.Texture = _character.CharacterPictures[first].Picture;
else
_characterPicturePreview.Texture = null;
_characterPicturePreview.Visible = _character.IsValid();
}
private void OnItemSelected(int index)
{
_serializedObject.GetProperty(nameof(SpeakAction.CharacterIndex)).SetValue<int>(index);
UpdateUI();
}
private void OnPropertyChanged(SerializedProperty property)
{
if (property.IsValid() && property.PropertyType.Equals(typeof(DialogueCharacter)))
{
UpdateUI();
}
}
}
private sealed class SpeakActionInputSettingsWidget : Widget
{
private Layout _content;
private Widget _waitForInputContainer;
private SerializedObject _serializedObject;
public SpeakActionInputSettingsWidget(SerializedObject so, Widget parent) : base(parent)
{
Name = "SpeakActionInputSettings";
_serializedObject = so;
_serializedObject.OnPropertyChanged += OnPropertyChanged;
Layout = Layout.Column();
_content = Layout;
Rebuild();
}
public void Rebuild()
{
Layout inputTypeLayout = Layout.Row();
inputTypeLayout.Alignment = TextFlag.LeftCenter;
Label inputTypeLabel = new Label("Input State")
{
ContentMargins = new Sandbox.UI.Margin(5, 0, 5, 0),
ToolTip = "How the dialogue system should handle input.",
FixedWidth = 125
};
EnumControlWidget inputTypeWidget = new EnumControlWidget(_serializedObject.GetProperty(nameof(SpeakAction.DialogueInputState)));
inputTypeWidget.MaximumWidth = 375;
inputTypeLayout.Add(inputTypeLabel);
inputTypeLayout.Add(inputTypeWidget);
inputTypeLayout.Margin = new Sandbox.UI.Margin(0, 1, 0, 1);
_content.Add(inputTypeLayout);
_waitForInputContainer = new Widget(this);
_waitForInputContainer.Layout = Layout.Row();
_waitForInputContainer.Layout.Alignment = TextFlag.LeftCenter;
Label waitInputDelayLabel = new Label("Wait For Input Delay")
{
ContentMargins = new Sandbox.UI.Margin(5, 0, 5, 0),
ToolTip = "How long it should wait before playing.",
FixedWidth = 125
};
FloatControlWidget waitInputDelayWidget = new FloatControlWidget(_serializedObject.GetProperty(nameof(SpeakAction.WaitForInputDelay)));
waitInputDelayWidget.MaximumWidth = 375;
_waitForInputContainer.Layout.Add(waitInputDelayLabel);
_waitForInputContainer.Layout.Add(waitInputDelayWidget);
_waitForInputContainer.Visible = _serializedObject.GetProperty(nameof(SpeakAction.DialogueInputState)).GetValue<DialogueInputState>() == DialogueInputState.WaitForSeconds;
_waitForInputContainer.ContentMargins = new Sandbox.UI.Margin(0, 1, 0, 1);
_content.Add(_waitForInputContainer);
}
private void OnPropertyChanged(SerializedProperty prop)
{
if (prop.PropertyType.Equals(typeof(DialogueInputState)))
{
if (prop.GetValue<DialogueInputState>() == DialogueInputState.WaitForSeconds)
_waitForInputContainer.Visible = true;
else
_waitForInputContainer.Visible = false;
}
}
public override void OnDestroyed()
{
_serializedObject.OnPropertyChanged -= OnPropertyChanged;
}
}
private sealed class SpeakActionWriteSettingsWidget : Widget
{
private Layout _content;
private Widget _writeSpeedContainer;
private SerializedObject _serializedObject;
public SpeakActionWriteSettingsWidget(SerializedObject so, Widget parent) : base(parent)
{
Name = "SpeakActionWriteSettings";
_serializedObject = so;
_serializedObject.OnPropertyChanged += OnPropertyChanged;
Layout = Layout.Column();
_content = Layout;
Rebuild();
}
public void Rebuild()
{
Layout writingEffectLayout = Layout.Row();
writingEffectLayout.Alignment = TextFlag.LeftCenter;
Label writingEffectLabel = new Label("Use Writing effect")
{
ContentMargins = new Sandbox.UI.Margin(5, 0, 5, 0),
ToolTip = "If it should use the writing effect.",
FixedWidth = 125
};
BoolControlWidget writingEffectWidget = new BoolControlWidget(_serializedObject.GetProperty(nameof(SpeakAction.UseWritingEffect)));
writingEffectLayout.Add(writingEffectLabel);
writingEffectLayout.Add(writingEffectWidget);
writingEffectLayout.Margin = new Sandbox.UI.Margin(0, 1, 0, 1);
_content.Add(writingEffectLayout);
_writeSpeedContainer = new Widget(this);
_writeSpeedContainer.Layout = Layout.Row();
_writeSpeedContainer.Layout.Alignment = TextFlag.LeftCenter;
Label writeSpeedLabel = new Label("Write speed")
{
ContentMargins = new Sandbox.UI.Margin(5, 0, 5, 0),
ToolTip = "How fast the text effect types.",
FixedWidth = 125
};
FloatControlWidget writeSpeedWidget = new FloatControlWidget(_serializedObject.GetProperty(nameof(SpeakAction.WriteSpeed)));
writeSpeedWidget.MaximumWidth = 375;
_writeSpeedContainer.Layout.Add(writeSpeedLabel);
_writeSpeedContainer.Layout.Add(writeSpeedWidget);
_writeSpeedContainer.Visible = _serializedObject.GetProperty(nameof(SpeakAction.UseWritingEffect)).GetValue<bool>();
_writeSpeedContainer.ContentMargins = new Sandbox.UI.Margin(0, 1, 0, 1);
_content.Add(_writeSpeedContainer);
}
private void OnPropertyChanged(SerializedProperty prop)
{
if (prop.Name.Equals(nameof(SpeakAction.UseWritingEffect)))
{
_writeSpeedContainer.Visible = prop.GetValue<bool>();
}
}
public override void OnDestroyed()
{
if (_serializedObject != null)
_serializedObject.OnPropertyChanged -= OnPropertyChanged;
}
}
private sealed class SpeakActionAudioSettingsWidget : Widget
{
private readonly Layout _content;
private Widget _audioSettings;
private Widget _audioDelayContainer;
private SerializedObject _serializedObject;
public SpeakActionAudioSettingsWidget(SerializedObject so, Widget parent) : base(parent)
{
Name = "SpeakActionAudioSettings";
_serializedObject = so;
_serializedObject.OnPropertyChanged += OnPropertyChanged;
Layout = Layout.Column();
_content = Layout;
Rebuild();
}
public void Rebuild()
{
//Audio Type
Layout audioTypeLayout = Layout.Row();
audioTypeLayout.Alignment = TextFlag.LeftCenter;
Label audioTypeLabel = new Label("Audio Type")
{
ContentMargins = new Sandbox.UI.Margin(5, 0, 5, 0),
ToolTip = "How the audio should be played.",
FixedWidth = 100
};
EnumControlWidget audioTypeWidget = new EnumControlWidget(_serializedObject.GetProperty(nameof(SpeakAction.AudioType)));
audioTypeWidget.MaximumWidth = 400;
audioTypeLayout.Add(audioTypeLabel);
audioTypeLayout.Add(audioTypeWidget);
audioTypeLayout.Margin = new Sandbox.UI.Margin(0, 1, 0, 1);
_content.Add(audioTypeLayout);
_audioSettings = new Widget(this);
_audioSettings.Layout = Layout.Column();
//Sound Event
Layout soundEventLayout = Layout.Row();
soundEventLayout.Alignment = TextFlag.LeftCenter;
Label soundEventLabel = new Label("Sound Event")
{
ContentMargins = new Sandbox.UI.Margin(5, 0, 5, 0),
ToolTip = "The audio that should be played.",
FixedWidth = 100
};
ControlWidget soundEventWidget = ControlWidget.Create(_serializedObject.GetProperty(nameof(SpeakAction.SoundEvent)));
soundEventWidget.MaximumWidth = 400;
soundEventLayout.Add(soundEventLabel);
soundEventLayout.Add(soundEventWidget);
soundEventLayout.Margin = new Sandbox.UI.Margin(0, 1, 0, 1);
_audioSettings.Layout.Add(soundEventLayout);
//Use audio delay
Layout useDelayLayout = Layout.Row();
useDelayLayout.Alignment = TextFlag.LeftCenter;
Label delayAudioLabel = new Label("Use Audio Delay")
{
ContentMargins = new Sandbox.UI.Margin(5, 0, 5, 0),
ToolTip = "If the audi should be delayed.",
FixedWidth = 100
};
BoolControlWidget delayAudioWidget = new BoolControlWidget(_serializedObject.GetProperty(nameof(SpeakAction.UseAudioDelay)));
useDelayLayout.Add(delayAudioLabel);
useDelayLayout.Add(delayAudioWidget);
useDelayLayout.Margin = new Sandbox.UI.Margin(0, 1, 0, 1);
_audioSettings.Layout.Add(useDelayLayout);
//Delay
_audioDelayContainer = new Widget(this);
_audioDelayContainer.Layout = Layout.Row();
_audioDelayContainer.Layout.Alignment = TextFlag.LeftCenter;
Label delayLabel = new Label("Audio Delay")
{
ContentMargins = new Sandbox.UI.Margin(5, 0, 5, 0),
ToolTip = "How long the audio should delay in seconds.",
FixedWidth = 100
};
RangedFloatControlWidget delayWidget = new RangedFloatControlWidget(_serializedObject.GetProperty(nameof(SpeakAction.AudioDelay)));
delayWidget.MaximumWidth = 400;
_audioDelayContainer.Layout.Add(delayLabel);
_audioDelayContainer.Layout.Add(delayWidget);
_audioDelayContainer.Visible = _serializedObject.GetProperty(nameof(SpeakAction.UseAudioDelay)).GetValue<bool>();
_audioDelayContainer.ContentMargins = new Sandbox.UI.Margin(0, 1, 0, 1);
_audioSettings.Layout.Add(_audioDelayContainer);
_audioSettings.Visible = _serializedObject.GetProperty(nameof(SpeakAction.AudioType)).GetValue<DialogueAudioType>() != DialogueAudioType.None;
_content.Add(_audioSettings);
}
private void OnPropertyChanged(SerializedProperty prop)
{
if (prop.Name.Equals(nameof(SpeakAction.UseAudioDelay)))
{
_audioDelayContainer.Visible = prop.GetValue<bool>();
}
else if (prop.Name.Equals(nameof(SpeakAction.AudioType)))
{
_audioSettings.Visible = prop.GetValue<DialogueAudioType>() != DialogueAudioType.None;
}
}
public override void OnDestroyed()
{
if (_serializedObject != null)
_serializedObject.OnPropertyChanged -= OnPropertyChanged;
}
}
private sealed class SpeakActionTextControlWidget : TextAreaControlWidget
{
public SpeakActionTextControlWidget(SerializedProperty property) : base(property)
{
TextEdit.TranslucentBackground = true;
TextEdit.FixedHeight = 200;
TextEdit.HorizontalSizeMode = SizeMode.CanGrow;
}
public override bool SupportsMultiEdit => false;
}
}