mirror of
https://github.com/drewcassidy/KSP-Conformal-Decals.git
synced 2024-09-01 18:23:54 +00:00
Working color picker UI
This commit is contained in:
@ -30,6 +30,7 @@ namespace ConformalDecals.UI {
|
||||
get => _value;
|
||||
set {
|
||||
_value = value;
|
||||
_onValueChanged.Invoke(value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,16 @@
|
||||
using ConformalDecals.Util;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace ConformalDecals.UI {
|
||||
public class ColorBoxSlider : MonoBehaviour {
|
||||
[SerializeField] private ColorPickerController.ChannelUpdateEvent _onXChannelChanged = new ColorPickerController.ChannelUpdateEvent();
|
||||
[SerializeField] private ColorPickerController.ChannelUpdateEvent _onYChannelChanged = new ColorPickerController.ChannelUpdateEvent();
|
||||
[SerializeField] public ColorPickerController.SVUpdateEvent onValueChanged = new ColorPickerController.SVUpdateEvent();
|
||||
|
||||
[SerializeField] private Vector2 _value;
|
||||
[SerializeField] private Vector2Int _channel;
|
||||
[SerializeField] private bool _hsl;
|
||||
|
||||
[SerializeField] private BoxSlider _slider;
|
||||
[SerializeField] private Image _image;
|
||||
|
||||
private static readonly int Hue = Shader.PropertyToID("_Hue");
|
||||
|
||||
private bool _ignoreUpdates;
|
||||
|
||||
public Vector2 Value {
|
||||
get => _value;
|
||||
@ -22,31 +18,46 @@ namespace ConformalDecals.UI {
|
||||
_value.x = Mathf.Clamp01(value.x);
|
||||
_value.y = Mathf.Clamp01(value.y);
|
||||
UpdateSlider();
|
||||
OnChannelUpdate();
|
||||
UpdateChannels();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnColorUpdate(Color rgb, Util.ColorHSV hsv) {
|
||||
if (_ignoreUpdates) return;
|
||||
|
||||
_image.material.SetColor(PropertyIDs._Color, (Vector4) hsv);
|
||||
|
||||
_value.x = hsv.s;
|
||||
_value.y = hsv.v;
|
||||
UpdateSlider();
|
||||
}
|
||||
|
||||
public void OnSliderUpdate(Vector2 value) {
|
||||
_value = value;
|
||||
OnChannelUpdate();
|
||||
}
|
||||
|
||||
public void OnChannelUpdate() {
|
||||
_onXChannelChanged.Invoke(_value.x, _channel.x, _hsl);
|
||||
_onYChannelChanged.Invoke(_value.y, _channel.y, _hsl);
|
||||
}
|
||||
|
||||
public void OnColorUpdate(Color rgb, ColorHSL hsl) {
|
||||
Vector2 newValue;
|
||||
newValue.x = _hsl ? hsl[_channel.x] : rgb[_channel.x];
|
||||
newValue.y = _hsl ? hsl[_channel.y] : rgb[_channel.y];
|
||||
Value = newValue;
|
||||
if (_ignoreUpdates) return;
|
||||
|
||||
_image.material.SetFloat(Hue, hsl.h);
|
||||
_value = value;
|
||||
UpdateChannels();
|
||||
}
|
||||
|
||||
public void UpdateSlider() {
|
||||
private void Awake() {
|
||||
var boxSlider = gameObject.GetComponentInChildren<BoxSlider>();
|
||||
boxSlider.OnValueChanged.AddListener(OnSliderUpdate);
|
||||
}
|
||||
|
||||
private void UpdateChannels() {
|
||||
_ignoreUpdates = true;
|
||||
|
||||
onValueChanged.Invoke(_value);
|
||||
|
||||
_ignoreUpdates = false;
|
||||
}
|
||||
|
||||
private void UpdateSlider() {
|
||||
_ignoreUpdates = true;
|
||||
|
||||
_slider.Value = _value;
|
||||
|
||||
_ignoreUpdates = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
using ConformalDecals.Util;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace ConformalDecals.UI {
|
||||
public class ColorChannelSlider : MonoBehaviour {
|
||||
[SerializeField] private ColorPickerController.ChannelUpdateEvent _onChannelChanged = new ColorPickerController.ChannelUpdateEvent();
|
||||
[SerializeField] public ColorPickerController.ChannelUpdateEvent onChannelChanged = new ColorPickerController.ChannelUpdateEvent();
|
||||
|
||||
[SerializeField] private float _value;
|
||||
[SerializeField] private int _channel;
|
||||
[SerializeField] private bool _hsl;
|
||||
[SerializeField] private bool _hsv;
|
||||
|
||||
[SerializeField] private Selectable _textBox;
|
||||
[SerializeField] private Slider _slider;
|
||||
@ -23,17 +22,27 @@ namespace ConformalDecals.UI {
|
||||
_value = Mathf.Clamp01(value);
|
||||
UpdateSlider();
|
||||
UpdateTextbox();
|
||||
OnChannelUpdate();
|
||||
UpdateChannel();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnColorUpdate(Color rgb, Util.ColorHSV hsv) {
|
||||
if (_ignoreUpdates) return;
|
||||
|
||||
_image.material.SetColor(PropertyIDs._Color, _hsv ? (Color) (Vector4) hsv : rgb);
|
||||
|
||||
_value = _hsv ? hsv[_channel] : rgb[_channel];
|
||||
UpdateSlider();
|
||||
UpdateTextbox();
|
||||
}
|
||||
|
||||
public void OnTextBoxUpdate(string text) {
|
||||
if (_ignoreUpdates) return;
|
||||
|
||||
if (byte.TryParse(text, out byte byteValue)) {
|
||||
_value = (float) byteValue / 255;
|
||||
UpdateSlider();
|
||||
OnChannelUpdate();
|
||||
UpdateChannel();
|
||||
}
|
||||
else {
|
||||
// value is invalid, reset value
|
||||
@ -46,25 +55,20 @@ namespace ConformalDecals.UI {
|
||||
|
||||
_value = value;
|
||||
UpdateTextbox();
|
||||
OnChannelUpdate();
|
||||
UpdateChannel();
|
||||
}
|
||||
|
||||
public void OnChannelUpdate() {
|
||||
_onChannelChanged.Invoke(_value, _channel, _hsl);
|
||||
private void UpdateChannel() {
|
||||
onChannelChanged.Invoke(_value, _channel, _hsv);
|
||||
}
|
||||
|
||||
public void OnColorUpdate(Color rgb, ColorHSL hsl) {
|
||||
_image.material.SetColor(PropertyIDs._Color, rgb);
|
||||
Value = _hsl ? hsl[_channel] : rgb[_channel];
|
||||
}
|
||||
|
||||
public void UpdateSlider() {
|
||||
private void UpdateSlider() {
|
||||
_ignoreUpdates = true;
|
||||
_slider.value = _value;
|
||||
_ignoreUpdates = false;
|
||||
}
|
||||
|
||||
public void UpdateTextbox() {
|
||||
private void UpdateTextbox() {
|
||||
if (_textBox == null) return;
|
||||
|
||||
_ignoreUpdates = true;
|
||||
|
@ -8,12 +8,15 @@ using UnityEngine.UI;
|
||||
namespace ConformalDecals.UI {
|
||||
public class ColorPickerController : MonoBehaviour {
|
||||
[Serializable]
|
||||
public class ColorUpdateEvent : UnityEvent<Color, ColorHSL> { }
|
||||
public class ColorUpdateEvent : UnityEvent<Color, Util.ColorHSV> { }
|
||||
|
||||
[Serializable]
|
||||
public class ChannelUpdateEvent : UnityEvent<float, int, bool> { }
|
||||
|
||||
[SerializeField] private ColorUpdateEvent _onColorChanged = new ColorUpdateEvent();
|
||||
|
||||
[Serializable]
|
||||
public class SVUpdateEvent : UnityEvent<Vector2> { }
|
||||
|
||||
[SerializeField] public ColorUpdateEvent onColorChanged = new ColorUpdateEvent();
|
||||
|
||||
[SerializeField] private Color _value;
|
||||
[SerializeField] private Image _previewImage;
|
||||
@ -29,23 +32,23 @@ namespace ConformalDecals.UI {
|
||||
}
|
||||
}
|
||||
|
||||
public ColorHSL HSL {
|
||||
get => ColorHSL.RGB2HSL(_value);
|
||||
public Util.ColorHSV HSV {
|
||||
get => Util.ColorHSV.RGB2HSV(_value);
|
||||
set {
|
||||
_value = ColorHSL.HSL2RGB(value);
|
||||
_value = Util.ColorHSV.HSV2RGB(value);
|
||||
OnColorUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static ColorPickerController Create(Color rgb, UnityAction<Color, ColorHSL> colorUpdateCallback) {
|
||||
public static ColorPickerController Create(Color rgb, UnityAction<Color, Util.ColorHSV> colorUpdateCallback) {
|
||||
var menu = Instantiate(UILoader.ColorPickerPrefab, MainCanvasUtil.MainCanvas.transform, true);
|
||||
menu.AddComponent<DragPanel>();
|
||||
MenuNavigation.SpawnMenuNavigation(menu, Navigation.Mode.Automatic, true);
|
||||
|
||||
var controller = menu.GetComponent<ColorPickerController>();
|
||||
controller.RGB = rgb;
|
||||
controller._onColorChanged.AddListener(colorUpdateCallback);
|
||||
controller.onColorChanged.AddListener(colorUpdateCallback);
|
||||
return controller;
|
||||
}
|
||||
|
||||
@ -53,9 +56,30 @@ namespace ConformalDecals.UI {
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
public void OnChannelUpdate(float value, int channel, bool hsv) {
|
||||
if (hsv) {
|
||||
var newHSV = HSV;
|
||||
newHSV[channel] = value;
|
||||
HSV = newHSV;
|
||||
}
|
||||
else {
|
||||
var newRGB = RGB;
|
||||
newRGB[channel] = value;
|
||||
RGB = newRGB;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSVUpdate(Vector2 sv) {
|
||||
var newHSV = HSV;
|
||||
newHSV.s = sv.x;
|
||||
newHSV.v = sv.y;
|
||||
HSV = newHSV;
|
||||
}
|
||||
|
||||
public void OnColorUpdate() {
|
||||
_onColorChanged.Invoke(RGB, HSL);
|
||||
onColorChanged.Invoke(RGB, HSV);
|
||||
_previewImage.material.SetColor(PropertyIDs._Color, RGB);
|
||||
UpdateHexColor();
|
||||
}
|
||||
|
||||
public void OnHexColorUpdate(string text) {
|
||||
@ -70,23 +94,24 @@ namespace ConformalDecals.UI {
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateHexColor() {
|
||||
_ignoreUpdate = true;
|
||||
((TMP_InputField) _hexTextBox).text = $"{RGB.r:x2}{RGB.g:x2}{RGB.b:x2}";
|
||||
_ignoreUpdate = false;
|
||||
private void Awake() {
|
||||
foreach (var slider in gameObject.GetComponentsInChildren<ColorChannelSlider>()) {
|
||||
slider.onChannelChanged.AddListener(OnChannelUpdate);
|
||||
onColorChanged.AddListener(slider.OnColorUpdate);
|
||||
}
|
||||
|
||||
foreach (var box in gameObject.GetComponentsInChildren<ColorBoxSlider>()) {
|
||||
box.onValueChanged.AddListener(OnSVUpdate);
|
||||
onColorChanged.AddListener(box.OnColorUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnChannelUpdate(float value, int channel, bool hsl) {
|
||||
if (hsl) {
|
||||
var newHSL = HSL;
|
||||
newHSL[channel] = value;
|
||||
HSL = newHSL;
|
||||
}
|
||||
else {
|
||||
var newRGB = RGB;
|
||||
newRGB[channel] = value;
|
||||
RGB = newRGB;
|
||||
}
|
||||
private void UpdateHexColor() {
|
||||
_ignoreUpdate = true;
|
||||
var byteColor = (Color32) RGB;
|
||||
var hexColor = $"{byteColor.r:x2}{byteColor.g:x2}{byteColor.b:x2}";
|
||||
((TMP_InputField) _hexTextBox).text = hexColor;
|
||||
_ignoreUpdate = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ namespace ConformalDecals.UI {
|
||||
[Serializable]
|
||||
public class FontUpdateEvent : UnityEvent<DecalFont> { }
|
||||
|
||||
[SerializeField] private FontUpdateEvent _onFontChanged = new FontUpdateEvent();
|
||||
[SerializeField] public FontUpdateEvent onFontChanged = new FontUpdateEvent();
|
||||
|
||||
[SerializeField] private GameObject _menuItem;
|
||||
[SerializeField] private GameObject _menuList;
|
||||
@ -25,7 +25,7 @@ namespace ConformalDecals.UI {
|
||||
|
||||
var controller = menu.GetComponent<FontMenuController>();
|
||||
controller._currentFont = currentFont;
|
||||
controller._onFontChanged.AddListener(fontUpdateCallback);
|
||||
controller.onFontChanged.AddListener(fontUpdateCallback);
|
||||
|
||||
controller.Populate(fonts);
|
||||
return controller;
|
||||
@ -37,7 +37,7 @@ namespace ConformalDecals.UI {
|
||||
|
||||
public void OnFontSelected(DecalFont font) {
|
||||
_currentFont = font ?? throw new ArgumentNullException(nameof(font));
|
||||
_onFontChanged.Invoke(_currentFont);
|
||||
onFontChanged.Invoke(_currentFont);
|
||||
}
|
||||
|
||||
public void Populate(IEnumerable<DecalFont> fonts) {
|
||||
|
@ -10,7 +10,7 @@ namespace ConformalDecals.UI {
|
||||
[Serializable]
|
||||
public class TextUpdateEvent : UnityEvent<DecalText> { }
|
||||
|
||||
[SerializeField] private TextUpdateEvent _onTextUpdate = new TextUpdateEvent();
|
||||
[SerializeField] public TextUpdateEvent onTextUpdate = new TextUpdateEvent();
|
||||
|
||||
[SerializeField] private Selectable _textBox;
|
||||
[SerializeField] private Button _fontButton;
|
||||
@ -32,7 +32,7 @@ namespace ConformalDecals.UI {
|
||||
|
||||
var controller = window.GetComponent<TextEntryController>();
|
||||
controller._decalText = text;
|
||||
controller._onTextUpdate.AddListener(textUpdateCallback);
|
||||
controller.onTextUpdate.AddListener(textUpdateCallback);
|
||||
|
||||
return controller;
|
||||
}
|
||||
@ -57,7 +57,7 @@ namespace ConformalDecals.UI {
|
||||
}
|
||||
|
||||
public void OnAnyUpdate() {
|
||||
_onTextUpdate.Invoke(_decalText);
|
||||
onTextUpdate.Invoke(_decalText);
|
||||
}
|
||||
|
||||
public void OnTextUpdate(string newText) {
|
||||
|
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@ -63,7 +62,7 @@ namespace ConformalDecals.UI {
|
||||
ProcessBoxSlider(tag.gameObject, skin.horizontalSlider, skin.horizontalSliderThumb);
|
||||
break;
|
||||
case UITag.UIType.Slider:
|
||||
ProcessSlider(tag.gameObject, skin.horizontalSlider, skin.horizontalSliderThumb, skin.verticalSlider, skin.verticalSliderThumb);
|
||||
ProcessSlider(tag.gameObject, skin.horizontalSlider, skin.horizontalSliderThumb, skin.horizontalSlider, skin.horizontalSliderThumb);
|
||||
break;
|
||||
case UITag.UIType.Box:
|
||||
ProcessSelectable(tag.gameObject, skin.box);
|
||||
@ -82,7 +81,10 @@ namespace ConformalDecals.UI {
|
||||
}
|
||||
|
||||
private static void ProcessImage(GameObject gameObject, UIStyle style) {
|
||||
ProcessImage(gameObject.GetComponent<Image>(), style.normal);
|
||||
var image = gameObject.GetComponent<Image>();
|
||||
if (image != null) {
|
||||
ProcessImage(image, style.normal);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessImage(Image image, UIStyleState state) {
|
||||
@ -135,10 +137,9 @@ namespace ConformalDecals.UI {
|
||||
|
||||
ProcessSelectable(gameObject, thumbStyle);
|
||||
|
||||
var back = gameObject.transform.Find("Background").GetComponent<Image>();
|
||||
var back = gameObject.transform.Find("Background");
|
||||
if (back != null) {
|
||||
back.sprite = sliderStyle.normal.background;
|
||||
back.type = Image.Type.Sliced;
|
||||
ProcessImage(back.gameObject, sliderStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,9 +147,9 @@ namespace ConformalDecals.UI {
|
||||
private static void ProcessBoxSlider(GameObject gameObject, UIStyle backgroundStyle, UIStyle thumbStyle) {
|
||||
ProcessSelectable(gameObject, thumbStyle);
|
||||
|
||||
var background = gameObject.transform.Find("Background").gameObject;
|
||||
var background = gameObject.transform.Find("Background");
|
||||
if (background != null) {
|
||||
ProcessImage(background, backgroundStyle);
|
||||
ProcessImage(background.gameObject, backgroundStyle);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user