//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
//**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************//
using System;
using System.Collections.Generic;
using bs;
namespace bs.Editor
{
/** @addtogroup Inspectors
* @{
*/
///
/// Renders an inspector for the resource.
///
[CustomInspector(typeof(GUISkin))]
internal class GUISkinInspector : Inspector
{
private GUIDictionaryField valuesField;
private Dictionary styles = new Dictionary();
///
protected internal override void Initialize()
{
LoadResource();
BuildGUI();
}
///
protected internal override InspectableState Refresh(bool force = false)
{
valuesField.Refresh(force);
return InspectableState.NotModified;
}
///
/// Recreates all the GUI elements used by this inspector.
///
private void BuildGUI()
{
Layout.Clear();
styles.Clear();
GUISkin guiSkin = InspectedObject as GUISkin;
if (guiSkin == null)
return;
string[] styleNames = guiSkin.StyleNames;
foreach (var styleName in styleNames)
styles[styleName] = guiSkin.GetStyle(styleName);
valuesField = GUIDictionaryField.Create
(new LocEdString("Styles"), styles, Layout);
valuesField.IsExpanded = Persistent.GetBool("valuesField_Expanded");
valuesField.OnExpand += x => Persistent.SetBool("valuesField_Expanded", x);
valuesField.OnChanged += x =>
{
if (x != null)
{
foreach (var KVP in x)
{
if (guiSkin.HasStyle(KVP.Key))
{
GUIElementStyle oldValue = guiSkin.GetStyle(KVP.Key);
if (oldValue != KVP.Value)
guiSkin.SetStyle(KVP.Key, KVP.Value);
}
else
guiSkin.SetStyle(KVP.Key, KVP.Value);
}
string[] oldStyleNames = guiSkin.StyleNames;
foreach (var styleName in oldStyleNames)
{
if (!x.ContainsKey(styleName))
guiSkin.RemoveStyle(styleName);
}
styles = x;
}
else
{
foreach (var KVP in styles)
guiSkin.RemoveStyle(KVP.Key);
styles.Clear();
}
EditorApplication.SetDirty(guiSkin);
};
valuesField.OnValueChanged += x =>
{
guiSkin.SetStyle(x, styles[x]);
EditorApplication.SetDirty(guiSkin);
};
valuesField.OnValueRemoved += x =>
{
guiSkin.RemoveStyle(x);
EditorApplication.SetDirty(guiSkin);
};
Layout.AddSpace(10);
}
///
/// Row element used for displaying GUI for GUI element style dictionary elements.
///
private class GUIElementStyleEntry : GUIDictionaryFieldRow
{
private GUITextField keyField;
private GUIElementStyleGUI valueField;
///
protected override GUILayoutX CreateKeyGUI(GUILayoutY layout)
{
GUILayoutX titleLayout = layout.AddLayoutX();
keyField = new GUITextField(new LocEdString("Name"));
titleLayout.AddElement(keyField);
keyField.OnChanged += SetKey;
return titleLayout;
}
///
protected override void CreateValueGUI(GUILayoutY layout)
{
if(valueField == null)
valueField = new GUIElementStyleGUI();
valueField.BuildGUI(layout, Depth);
}
///
protected override void OnEditModeChanged(bool editMode)
{
keyField.Disabled = !editMode;
}
///
protected internal override InspectableState Refresh(bool force)
{
keyField.Value = GetKey();
return valueField.Refresh(GetValue());
}
}
///
/// Creates GUI elements for editing/displaying
///
private class GUIElementStyleGUI
{
private const int IndentAmount = 5;
private GUIResourceField fontField;
private GUIIntField fontSizeField;
private GUIEnumField horzAlignField;
private GUIEnumField vertAlignField;
private GUIEnumField imagePositionField;
private GUIToggleField wordWrapField;
private GUIElementStateStyleGUI normalGUI;
private GUIElementStateStyleGUI hoverGUI;
private GUIElementStateStyleGUI activeGUI;
private GUIElementStateStyleGUI focusedGUI;
private GUIElementStateStyleGUI normalOnGUI;
private GUIElementStateStyleGUI hoverOnGUI;
private GUIElementStateStyleGUI activeOnGUI;
private GUIElementStateStyleGUI focusedOnGUI;
private RectOffsetGUI borderGUI;
private RectOffsetGUI marginsGUI;
private RectOffsetGUI contentOffsetGUI;
private GUIToggleField fixedWidthField;
private GUIIntField widthField;
private GUIIntField minWidthField;
private GUIIntField maxWidthField;
private GUIToggleField fixedHeightField;
private GUIIntField heightField;
private GUIIntField minHeightField;
private GUIIntField maxHeightField;
private GUIElementStyle style;
private bool isExpanded;
private InspectableState modifiedState;
///
/// Creates a new GUI element style GUI.
///
public GUIElementStyleGUI()
{
normalGUI = new GUIElementStateStyleGUI();
hoverGUI = new GUIElementStateStyleGUI();
activeGUI = new GUIElementStateStyleGUI();
focusedGUI = new GUIElementStateStyleGUI();
normalOnGUI = new GUIElementStateStyleGUI();
hoverOnGUI = new GUIElementStateStyleGUI();
activeOnGUI = new GUIElementStateStyleGUI();
focusedOnGUI = new GUIElementStateStyleGUI();
}
///
/// Builds GUI for the specified GUI element style.
///
/// Layout to append the GUI elements to.
/// Determines the depth at which the element is rendered.
public void BuildGUI(GUILayout layout, int depth)
{
short backgroundDepth = (short)(Inspector.START_BACKGROUND_DEPTH - depth - 1);
string bgPanelStyle = depth % 2 == 0
? EditorStylesInternal.InspectorContentBgAlternate
: EditorStylesInternal.InspectorContentBg;
GUIToggle foldout = new GUIToggle(new LocEdString("Style"), EditorStyles.Foldout);
foldout.AcceptsKeyFocus = false;
GUITexture inspectorContentBg = new GUITexture(null, bgPanelStyle);
layout.AddElement(foldout);
GUIPanel panel = layout.AddPanel();
GUIPanel backgroundPanel = panel.AddPanel(backgroundDepth);
backgroundPanel.AddElement(inspectorContentBg);
GUILayoutX guiIndentLayoutX = panel.AddLayoutX();
guiIndentLayoutX.AddSpace(IndentAmount);
GUILayoutY guiIndentLayoutY = guiIndentLayoutX.AddLayoutY();
guiIndentLayoutY.AddSpace(IndentAmount);
GUILayoutY contentLayout = guiIndentLayoutY.AddLayoutY();
guiIndentLayoutY.AddSpace(IndentAmount);
guiIndentLayoutX.AddSpace(IndentAmount);
fontField = new GUIResourceField(typeof (Font), new LocEdString("Font"));
fontSizeField = new GUIIntField(new LocEdString("Font size"));
horzAlignField = new GUIEnumField(typeof (TextHorzAlign), new LocEdString("Horizontal alignment"));
vertAlignField = new GUIEnumField(typeof(TextVertAlign), new LocEdString("Vertical alignment"));
imagePositionField = new GUIEnumField(typeof(GUIImagePosition), new LocEdString("Image position"));
wordWrapField = new GUIToggleField(new LocEdString("Word wrap"));
contentLayout.AddElement(fontField);
contentLayout.AddElement(fontSizeField);
contentLayout.AddElement(horzAlignField);
contentLayout.AddElement(vertAlignField);
contentLayout.AddElement(imagePositionField);
contentLayout.AddElement(wordWrapField);
normalGUI.BuildGUI(new LocEdString("Normal"), contentLayout);
hoverGUI.BuildGUI(new LocEdString("Hover"), contentLayout);
activeGUI.BuildGUI(new LocEdString("Active"), contentLayout);
focusedGUI.BuildGUI(new LocEdString("Focused"), contentLayout);
normalOnGUI.BuildGUI(new LocEdString("NormalOn"), contentLayout);
hoverOnGUI.BuildGUI(new LocEdString("HoverOn"), contentLayout);
activeOnGUI.BuildGUI(new LocEdString("ActiveOn"), contentLayout);
focusedOnGUI.BuildGUI(new LocEdString("FocusedOn"), contentLayout);
borderGUI = new RectOffsetGUI(new LocEdString("Border"), contentLayout);
marginsGUI = new RectOffsetGUI(new LocEdString("Margins"), contentLayout);
contentOffsetGUI = new RectOffsetGUI(new LocEdString("Content offset"), contentLayout);
fixedWidthField = new GUIToggleField(new LocEdString("Fixed width"));
widthField = new GUIIntField(new LocEdString("Width"));
minWidthField = new GUIIntField(new LocEdString("Min. width"));
maxWidthField = new GUIIntField(new LocEdString("Max. width"));
fixedHeightField = new GUIToggleField(new LocEdString("Fixed height"));
heightField = new GUIIntField(new LocEdString("Height"));
minHeightField = new GUIIntField(new LocEdString("Min. height"));
maxHeightField = new GUIIntField(new LocEdString("Max. height"));
contentLayout.AddElement(fixedWidthField);
contentLayout.AddElement(widthField);
contentLayout.AddElement(minWidthField);
contentLayout.AddElement(maxWidthField);
contentLayout.AddElement(fixedHeightField);
contentLayout.AddElement(heightField);
contentLayout.AddElement(minHeightField);
contentLayout.AddElement(maxHeightField);
foldout.OnToggled += x =>
{
panel.Active = x;
isExpanded = x;
};
fontField.OnChanged += x =>
{
Font font = Resources.Load(x.UUID);
GetStyle().Font = font;
MarkAsModified();
ConfirmModify();
};
fontSizeField.OnChanged += x => { GetStyle().FontSize = x; MarkAsModified(); };
fontSizeField.OnFocusLost += ConfirmModify;
fontSizeField.OnConfirmed += ConfirmModify;
horzAlignField.OnSelectionChanged += x =>
{
GetStyle().TextHorzAlign = (TextHorzAlign)x;
MarkAsModified();
ConfirmModify();
};
vertAlignField.OnSelectionChanged += x =>
{
GetStyle().TextVertAlign = (TextVertAlign)x;
MarkAsModified();
ConfirmModify();
};
imagePositionField.OnSelectionChanged += x =>
{
GetStyle().ImagePosition = (GUIImagePosition)x;
MarkAsModified();
ConfirmModify();
};
wordWrapField.OnChanged += x => { GetStyle().WordWrap = x; MarkAsModified(); ConfirmModify(); };
normalGUI.OnChanged += x => { GetStyle().Normal = x; MarkAsModified(); ConfirmModify(); };
hoverGUI.OnChanged += x => { GetStyle().Hover = x; MarkAsModified(); ConfirmModify(); };
activeGUI.OnChanged += x => { GetStyle().Active = x; MarkAsModified(); ConfirmModify(); };
focusedGUI.OnChanged += x => { GetStyle().Focused = x; MarkAsModified(); ConfirmModify(); };
normalOnGUI.OnChanged += x => { GetStyle().NormalOn = x; MarkAsModified(); ConfirmModify(); };
hoverOnGUI.OnChanged += x => { GetStyle().HoverOn = x; MarkAsModified(); ConfirmModify(); };
activeOnGUI.OnChanged += x => { GetStyle().ActiveOn = x; MarkAsModified(); ConfirmModify(); };
focusedOnGUI.OnChanged += x => { GetStyle().FocusedOn = x; MarkAsModified(); ConfirmModify(); };
borderGUI.OnChanged += x => { GetStyle().Border = x; MarkAsModified(); };
marginsGUI.OnChanged += x => { GetStyle().Margins = x; MarkAsModified(); };
contentOffsetGUI.OnChanged += x => { GetStyle().ContentOffset = x; MarkAsModified(); };
borderGUI.OnConfirmed += ConfirmModify;
marginsGUI.OnConfirmed += ConfirmModify;
contentOffsetGUI.OnConfirmed += ConfirmModify;
fixedWidthField.OnChanged += x => { GetStyle().FixedWidth = x; MarkAsModified(); ConfirmModify(); };
widthField.OnChanged += x => GetStyle().Width = x;
widthField.OnFocusLost += ConfirmModify;
widthField.OnConfirmed += ConfirmModify;
minWidthField.OnChanged += x => GetStyle().MinWidth = x;
minWidthField.OnFocusLost += ConfirmModify;
minWidthField.OnConfirmed += ConfirmModify;
maxWidthField.OnChanged += x => GetStyle().MaxWidth = x;
maxWidthField.OnFocusLost += ConfirmModify;
maxWidthField.OnConfirmed += ConfirmModify;
fixedHeightField.OnChanged += x => { GetStyle().FixedHeight = x; MarkAsModified(); ConfirmModify(); };
heightField.OnChanged += x => GetStyle().Height = x;
heightField.OnFocusLost += ConfirmModify;
heightField.OnConfirmed += ConfirmModify;
minHeightField.OnChanged += x => GetStyle().MinHeight = x;
minHeightField.OnFocusLost += ConfirmModify;
minHeightField.OnConfirmed += ConfirmModify;
maxHeightField.OnChanged += x => GetStyle().MaxHeight = x;
maxHeightField.OnFocusLost += ConfirmModify;
maxHeightField.OnConfirmed += ConfirmModify;
foldout.Value = isExpanded;
panel.Active = isExpanded;
}
///
/// Updates all GUI elements from the style if style changes.
///
/// Style to display in the GUI.
/// State representing was anything modified between two last calls to .
public InspectableState Refresh(GUIElementStyle style)
{
this.style = style;
InspectableState oldModifiedState = modifiedState;
if (modifiedState.HasFlag(InspectableState.Modified))
modifiedState = InspectableState.NotModified;
if (style == null)
return oldModifiedState;
fontField.Value = style.Font;
fontSizeField.Value = style.FontSize;
horzAlignField.Value = (ulong)style.TextHorzAlign;
vertAlignField.Value = (ulong)style.TextVertAlign;
imagePositionField.Value = (ulong)style.ImagePosition;
wordWrapField.Value = style.WordWrap;
normalGUI.Refresh(style.Normal);
hoverGUI.Refresh(style.Hover);
activeGUI.Refresh(style.Active);
focusedGUI.Refresh(style.Focused);
normalOnGUI.Refresh(style.NormalOn);
hoverOnGUI.Refresh(style.HoverOn);
activeOnGUI.Refresh(style.ActiveOn);
focusedOnGUI.Refresh(style.FocusedOn);
borderGUI.Refresh(style.Border);
marginsGUI.Refresh(style.Margins);
contentOffsetGUI.Refresh(style.ContentOffset);
fixedWidthField.Value = style.FixedWidth;
widthField.Value = style.Width;
minWidthField.Value = style.MinWidth;
maxWidthField.Value = style.MaxWidth;
fixedHeightField.Value = style.FixedHeight;
heightField.Value = style.Height;
minHeightField.Value = style.MinHeight;
maxHeightField.Value = style.MaxHeight;
widthField.Active = style.FixedWidth;
minWidthField.Active = !style.FixedWidth;
maxWidthField.Active = !style.FixedWidth;
heightField.Active = style.FixedHeight;
minHeightField.Active = !style.FixedHeight;
maxHeightField.Active = !style.FixedHeight;
return oldModifiedState;
}
///
/// Returns the style displayed in the GUI.
///
/// Style displayed in the GUI.
private GUIElementStyle GetStyle()
{
return style;
}
///
/// Marks the contents of the style as modified.
///
private void MarkAsModified()
{
modifiedState |= InspectableState.ModifyInProgress;
}
///
/// Confirms any queued modifications, signaling parent element.
///
private void ConfirmModify()
{
if (modifiedState.HasFlag(InspectableState.ModifyInProgress))
modifiedState |= InspectableState.Modified;
}
///
/// Creates GUI elements for editing/displaying
///
private class GUIElementStateStyleGUI
{
private GUIElementStateStyle state;
private GUIToggle foldout;
private GUIResourceField textureField;
private GUIColorField textColorField;
private bool isExpanded;
///
/// Triggered when some value in the style state changes.
///
public Action OnChanged;
///
/// Creates a new GUI element state style GUI.
///
public GUIElementStateStyleGUI()
{ }
///
/// Builds the GUI for the specified state style.
///
/// Text to display on the title bar.
/// Layout to append the GUI elements to.
public void BuildGUI(LocString title, GUILayout layout)
{
foldout = new GUIToggle(title, EditorStyles.Foldout);
textureField = new GUIResourceField(typeof(SpriteTexture), new LocEdString("Texture"));
textColorField = new GUIColorField(new LocEdString("Text color"));
foldout.AcceptsKeyFocus = false;
foldout.OnToggled += x =>
{
textureField.Active = x;
textColorField.Active = x;
isExpanded = x;
};
textureField.OnChanged += x =>
{
SpriteTexture texture = Resources.Load(x.UUID);
state.texture = texture;
if (OnChanged != null)
OnChanged(state);
};
textColorField.OnChanged += x =>
{
state.textColor = x;
if (OnChanged != null)
OnChanged(state);
};
layout.AddElement(foldout);
layout.AddElement(textureField);
layout.AddElement(textColorField);
foldout.Value = isExpanded;
textureField.Active = isExpanded;
textColorField.Active = isExpanded;
}
///
/// Updates all GUI elements from the current state values.
///
/// State object to display in the GUI.
public void Refresh(GUIElementStateStyle state)
{
this.state = state;
textureField.Value = state.texture;
textColorField.Value = state.textColor;
}
}
///
/// Creates GUI elements for editing/displaying
///
private class RectOffsetGUI
{
private RectOffset offset;
private GUIIntField offsetLeftField;
private GUIIntField offsetRightField;
private GUIIntField offsetTopField;
private GUIIntField offsetBottomField;
///
/// Triggered when some value in the offset rectangle changes.
///
public Action OnChanged;
///
/// Triggered when the user confirms input.
///
public Action OnConfirmed;
///
/// Creates a new rectangle offset GUI.
///
/// Text to display on the title bar.
/// Layout to append the GUI elements to.
public RectOffsetGUI(LocString title, GUILayout layout)
{
GUILayoutX rectLayout = layout.AddLayoutX();
rectLayout.AddElement(new GUILabel(title, GUIOption.FixedWidth(100)));
GUILayoutY rectContentLayout = rectLayout.AddLayoutY();
GUILayoutX rectTopRow = rectContentLayout.AddLayoutX();
GUILayoutX rectBotRow = rectContentLayout.AddLayoutX();
offsetLeftField = new GUIIntField(new LocEdString("Left"), 40);
offsetRightField = new GUIIntField(new LocEdString("Right"), 40);
offsetTopField = new GUIIntField(new LocEdString("Top"), 40);
offsetBottomField = new GUIIntField(new LocEdString("Bottom"), 40);
rectTopRow.AddElement(offsetLeftField);
rectTopRow.AddElement(offsetRightField);
rectBotRow.AddElement(offsetTopField);
rectBotRow.AddElement(offsetBottomField);
offsetLeftField.OnChanged += x =>
{
offset.left = x;
if(OnChanged != null)
OnChanged(offset);
};
offsetRightField.OnChanged += x =>
{
offset.right = x;
if (OnChanged != null)
OnChanged(offset);
};
offsetTopField.OnChanged += x =>
{
offset.top = x;
if (OnChanged != null)
OnChanged(offset);
};
offsetBottomField.OnChanged += x =>
{
offset.bottom = x;
if (OnChanged != null)
OnChanged(offset);
};
Action DoOnConfirmed = () =>
{
if (OnConfirmed != null)
OnConfirmed();
};
offsetLeftField.OnConfirmed += DoOnConfirmed;
offsetLeftField.OnFocusLost += DoOnConfirmed;
offsetRightField.OnConfirmed += DoOnConfirmed;
offsetRightField.OnFocusLost += DoOnConfirmed;
offsetTopField.OnConfirmed += DoOnConfirmed;
offsetTopField.OnFocusLost += DoOnConfirmed;
offsetBottomField.OnConfirmed += DoOnConfirmed;
offsetBottomField.OnFocusLost += DoOnConfirmed;
}
///
/// Updates all GUI elements from the offset.
///
/// Offset to update the GUI to.
public void Refresh(RectOffset offset)
{
this.offset = offset;
offsetLeftField.Value = offset.left;
offsetRightField.Value = offset.right;
offsetTopField.Value = offset.top;
offsetBottomField.Value = offset.bottom;
}
}
}
}
/** @} */
}