/// <inheritdoc/> public override void RenderControl( GuiActionsList actionsList, GUIStyle layoutStyle, GUILayoutOption[] layoutOptions) { using (new GUILayout.VerticalScope(GUI.skin.box)) { using (new GUILayout.HorizontalScope(GUIStyle.none)) { GUILayout.Label(caption); GUILayout.FlexibleSpace(); var toggleCaption = isExpanded ? "\u25b2 Collapse Group" : "\u25bc Expand Group"; if (GUILayout.Button(toggleCaption, layoutOptions)) { if (actionsList != null) { var isExpandedCopy = isExpanded; // Lambda needs a copy! actionsList.Add(() => isExpanded = !isExpanded); } else { isExpanded = !isExpanded; } } } if (isExpanded) { foreach (var control in adjustableControls) { control.RenderControl(actionsList, layoutStyle, layoutOptions); } } } }
/// <summary>Sets value to the controlled member.</summary> /// <typeparam name="T">The type of the member.</typeparam> /// <param name="value">The new value to set.</param> /// <param name="actionsList"> /// The actions list to submit the update actions into. If it's <c>null</c>, then the update and /// the notification will happen immediately. /// </param> protected void SetMemberValue <T>(T value, GuiActionsList actionsList = null) { if (actionsList != null) { actionsList.Add(() => SetMemberValueInternal(value)); } else { SetMemberValueInternal(value); } }
/// <summary>Method to have the control rendered ion GUI.</summary> /// <remarks>Call it from the <c>OnGUI</c> callback.</remarks> /// <param name="value">The source value.</param> /// <param name="ownLayoutStyle">The style to use when making own horizontal layout.</param> /// <param name="textfieldOptions">The options to apply to the input field.</param> /// <param name="onValueSet">The method to call when a value is applied.</param> /// <param name="actionsList">The action list to use to submit the value update job to.</param> /// <returns> /// The new value. It's the same as <paramref name="value"/> until user explicitly chose to set /// the value. /// </returns> public T UpdateFrame(T value, GUIStyle ownLayoutStyle, GUILayoutOption[] textfieldOptions, Action <T> onValueSet = null, GuiActionsList actionsList = null) { if (useOwnLayout) { GUILayout.BeginHorizontal(ownLayoutStyle); } var valueTxt = toStringConverter(value); currentTxt = currentTxt ?? valueTxt; var changed = currentTxt != valueTxt; bool validValue = true; try { currentValue = fromStringConverter(currentTxt); } catch (Exception) { currentValue = default(T); validValue = false; } using (new GuiColorScope(contentColor: validValue?Color.white: Color.red)) { currentTxt = GUILayout.TextField(changed ? currentTxt : valueTxt, textfieldOptions); } using (new GuiEnabledStateScope(changed)) { using (new GuiEnabledStateScope(changed && validValue)) { if (GUILayout.Button("S", GUILayout.ExpandWidth(false))) { value = currentValue; currentTxt = toStringConverter(value); if (onValueSet != null) { if (actionsList == null) { onValueSet(currentValue); } else { actionsList.Add(() => onValueSet(currentValue)); } } } } if (GUILayout.Button("C", GUILayout.ExpandWidth(false))) { currentTxt = valueTxt; } } if (useOwnLayout) { GUILayout.EndHorizontal(); } return(value); }
/// <inheritdoc/> public override void RenderControl( GuiActionsList actionsList, GUIStyle layoutStyle, GUILayoutOption[] layoutOptions) { GUI.changed = false; var value = GetMemberValue <bool>(); value = GUILayout.Toggle(value, caption, GUI.skin.toggle); if (GUI.changed) { SetMemberValue(value); } }
/// <summary>Makes a toggle control that fires a callback when the state changes.</summary> /// <remarks> /// The callbacks are only fired once for every state change, and are guaranteed to not be called /// during the layout phase. The callback is called *after* the state is updated. /// </remarks> /// <param name="btnState">The current toggle state.</param> /// <param name="guiCnt">The GUI content to present as the button's caption.</param> /// <param name="style">The GUI style of the control.</param> /// <param name="options"> /// The GUILayout options to apply to the control. It can be <c>null</c>. /// </param> /// <param name="fnOn"> /// The callback to call when the control is checked. Can be <c>null</c>. /// </param> /// <param name="fnOff">The callback to call when the control is checked. Can be <c>null</c>. /// </param> /// <param name="actionsList"> /// The action list to execute the callbacks thru. If the list is omitted, then the callback is /// fired right away. Otherwise, it's added to the list and executed when the list is triggered. /// </param> /// <returns>The new button toggle state.</returns> /// <seealso cref="GuiActionsList"/> public static bool Toggle(bool btnState, GUIContent guiCnt, GUIStyle style, GUILayoutOption[] options, Action fnOn, Action fnOff, GuiActionsList actionsList = null) { GUI.changed = false; var state = GUILayout.Toggle(btnState, guiCnt, style, options); if (Event.current.type != EventType.Layout) { if (!GUI.enabled) { state = false; } if (btnState != state) { btnState = state; if (btnState) { if (fnOn != null) { if (actionsList == null) { fnOn(); } else { actionsList.Add(fnOn); } } } else { if (fnOff != null) { if (actionsList == null) { fnOff(); } else { actionsList.Add(fnOff); } } } } } return(btnState); }
/// <summary>Makes a button that fires a callback when pressed or released.</summary> /// <remarks> /// The callbacks are only fired once for every state change, and are guarnteed to not be called /// during the layout phase. The callback is called *after* the state is updated. /// </remarks> /// <param name="btnState">The current press state of the button.</param> /// <param name="guiCnt">The GUI content to present as the button's caption.</param> /// <param name="style">The GUI style of the control.</param> /// <param name="options"> /// The GUILayout options to apply to the control. It can be <c>null</c>. /// </param> /// <param name="fnPush"> /// The callback to call when the button is pressed. Can be <c>null</c>. /// </param> /// <param name="fnRelease"> /// The callback to call when the button is released. Can be <c>null</c>. /// </param> /// <param name="actionsList"> /// The action list to execute the callbacks thru. If the list is omitted, then the callback is /// fired right away. Otherwise, it's added to the list and executed when the list is triggered. /// </param> /// <returns>The new button press state.</returns> /// <seealso cref="GuiActionsList"/> public static bool Push(bool btnState, GUIContent guiCnt, GUIStyle style, GUILayoutOption[] options, Action fnPush, Action fnRelease, GuiActionsList actionsList = null) { var state = GUILayout.RepeatButton(guiCnt, style, options); if (Event.current.type != EventType.Layout) { if (!GUI.enabled) { state = false; } if (state != btnState) { btnState = state; if (btnState) { if (fnPush != null) { if (actionsList == null) { fnPush(); } else { actionsList.Add(fnPush); } } } else { if (fnRelease != null) { if (actionsList == null) { fnRelease(); } else { actionsList.Add(fnRelease); } } } } } return(btnState); }
/// <inheritdoc/> public override void RenderControl( GuiActionsList actionsList, GUIStyle layoutStyle, GUILayoutOption[] layoutOptions) { if (useOwnLayout) { GUILayout.BeginHorizontal(layoutStyle); } var value = GetMemberValue <object>(); var idx = 0; if (GUILayout.Button("<", GUILayout.ExpandWidth(false))) { idx = -1; } var centeredTextStyle = new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleCenter }; GUILayout.Label(toStringConverter(value), centeredTextStyle, layoutOptions); if (GUILayout.Button(">", GUILayout.ExpandWidth(false))) { idx = 1; } if (useOwnLayout) { GUILayout.EndHorizontal(); } var newValue = value; if (idx != 0) { var pos = valueOptions.IndexOf(value); if (pos == -1) { pos = 0; } newValue = valueOptions[(valueOptions.Length + pos + idx) % valueOptions.Length]; } if (!newValue.Equals(value)) { SetMemberValue(newValue, actionsList); } }
/// <inheritdoc/> public abstract void RenderControl( GuiActionsList actionsList, GUIStyle layoutStyle, GUILayoutOption[] layoutOptions);
/// <inheritdoc/> public override void RenderControl( GuiActionsList actionsList, GUIStyle layoutStyle, GUILayoutOption[] layoutOptions) { if (useOwnLayout) { GUILayout.BeginHorizontal(layoutStyle); } var value = GetMemberValue <object>(); var valueTxt = value != null?valueTypeProto.SerializeToString(value) : NullValue; if (currentTxt == null) { currentTxt = valueTxt; isValid = true; } var changed = currentTxt != valueTxt; if (changed) { isValid = true; try { if (currentTxt.Trim() != NullValue) { valueTypeProto.ParseFromString(currentTxt, GetMemberType()); } } catch (Exception) { isValid = false; } } using (new GuiColorScope(contentColor: isValid?Color.white: Color.red)) { currentTxt = GUILayout.TextField(changed ? currentTxt : valueTxt, layoutOptions); } using (new GuiEnabledStateScope(changed)) { using (new GuiEnabledStateScope(changed && isValid)) { if (GUILayout.Button("S", GUILayout.ExpandWidth(false))) { if (currentTxt.Trim() != NullValue) { value = valueTypeProto.ParseFromString(currentTxt, GetMemberType()); currentTxt = valueTypeProto.SerializeToString(value); } else { value = null; currentTxt = NullValue; } SetMemberValue(value); } } if (GUILayout.Button("C", GUILayout.ExpandWidth(false))) { currentTxt = valueTxt; isValid = true; } } if (useOwnLayout) { GUILayout.EndHorizontal(); } }