Tanoda
SegmentedControl.cs
Go to the documentation of this file.
1
3
4using System;
5using System.Collections;
8
10{
11 // Segmented control, like a group of buttons
12 [AddComponentMenu("UI/Extensions/Segmented Control/Segmented Control")]
13 [RequireComponent(typeof(RectTransform))]
14 public class SegmentedControl : UIBehaviour
15 {
16 private Selectable[] m_segments;
17 [SerializeField]
18 [Tooltip("A GameObject with an Image to use as a separator between segments. Size of the RectTransform will determine the size of the separator used.\nNote, make sure to disable the separator GO so that it does not affect the scene")]
19 private Graphic m_separator;
20 private float m_separatorWidth = 0;
21 [SerializeField]
22 [Tooltip("When True, it allows each button to be toggled on/off")]
23 private bool m_allowSwitchingOff = false;
24 [SerializeField]
25 [Tooltip("The selected default for the control (zero indexed array)")]
26 private int m_selectedSegmentIndex = -1;
27 // Event delegates triggered on click.
28 [SerializeField]
29 [Tooltip("Event to fire once the selection has been changed")]
30 private SegmentSelectedEvent m_onValueChanged = new SegmentSelectedEvent();
31
32 internal Selectable selectedSegment;
33
34 protected float SeparatorWidth
35 {
36 get
37 {
38 if (m_separatorWidth == 0 && separator)
39 {
40 m_separatorWidth = separator.rectTransform.rect.width;
41 var image = separator.GetComponent<Image>();
42 if (image)
43 m_separatorWidth /= image.pixelsPerUnit;
44 }
45 return m_separatorWidth;
46 }
47 }
48
49 [Serializable]
50 public class SegmentSelectedEvent : UnityEvent<int> { }
51
52 public Selectable[] segments
53 {
54 get
55 {
56 if (m_segments == null || m_segments.Length == 0)
57 {
58 m_segments = GetChildSegments();
59 }
60 return m_segments;
61 }
62 }
63
64 public Graphic separator { get { return m_separator; } set { m_separator = value; m_separatorWidth = 0; LayoutSegments(); } }
65
66 public bool allowSwitchingOff { get { return m_allowSwitchingOff; } set { m_allowSwitchingOff = value; } }
67
69 {
70 get { return Array.IndexOf(segments, selectedSegment); }
71 set
72 {
73 value = Math.Max(value, -1);
74 value = Math.Min(value, segments.Length - 1);
75
76 m_selectedSegmentIndex = value;
77
78 if (selectedSegment)
79 {
80 var segment = selectedSegment.GetComponent<Segment>();
81 if (segment)
82 {
83 segment.selected = false;
84 }
85 selectedSegment = null;
86 }
87
88 if (value != -1)
89 {
90 selectedSegment = segments[value];
91 var segment = selectedSegment.GetComponent<Segment>();
92 if (segment)
93 {
94 segment.selected = true;
95 }
96 }
97 }
98 }
99
101 {
102 get { return m_onValueChanged; }
103 set { m_onValueChanged = value; }
104 }
105
107 { }
108
109 protected override void Start()
110 {
111 base.Start();
112
113 if (isActiveAndEnabled)
114 StartCoroutine(DelayedInit());
115 }
116
117 protected override void OnEnable()
118 {
119 StartCoroutine(DelayedInit());
120 }
121
122 IEnumerator DelayedInit()
123 {
124 yield return null;
125
127
128 if (m_selectedSegmentIndex != -1)
129 selectedSegmentIndex = m_selectedSegmentIndex;
130 }
131
132#if UNITY_EDITOR
133 protected override void OnValidate()
134 {
135 base.OnValidate();
136
137 if (isActiveAndEnabled)
138 StartCoroutine(DelayedInit());
139
140 if (m_selectedSegmentIndex > transform.childCount)
141 {
142 selectedSegmentIndex = transform.childCount - 1;
143 }
144 }
145#endif
146
147 private Selectable[] GetChildSegments()
148 {
149 var buttons = GetComponentsInChildren<Selectable>();
150 if (buttons.Length < 2)
151 {
152 throw new InvalidOperationException("A segmented control must have at least two Button children");
153 }
154
155 for (int i = 0; i < buttons.Length; i++)
156 {
157 var segment = buttons[i].GetComponent<Segment>();
158 if (segment != null)
159 {
160 segment.index = i;
161 segment.segmentedControl = this;
162 }
163 }
164
165 return buttons;
166 }
167
168 private void RecreateSprites()
169 {
170 for (int i = 0; i < segments.Length; i++)
171 {
172 if (segments[i].image == null)
173 continue;
174
175 var sprite = CutSprite(segments[i].image.sprite, i == 0, i == segments.Length - 1);
176 var segment = segments[i].GetComponent<Segment>();
177 if (segment)
178 {
179 segment.cutSprite = sprite;
180 }
181 segments[i].image.overrideSprite = sprite;
182 }
183 }
184
185 static internal Sprite CutSprite(Sprite sprite, bool leftmost, bool rightmost)
186 {
187 if (sprite.border.x == 0 || sprite.border.z == 0)
188 return sprite;
189
190 var rect = sprite.rect;
191 var border = sprite.border;
192
193 if (!leftmost)
194 {
195 rect.xMin = border.x;
196 border.x = 0;
197 }
198 if (!rightmost)
199 {
200 rect.xMax = border.z;
201 border.z = 0;
202 }
203
204 return Sprite.Create(sprite.texture, rect, sprite.pivot, sprite.pixelsPerUnit, 0, SpriteMeshType.FullRect, border);
205 }
206
207 public void LayoutSegments()
208 {
209 RecreateSprites();
210
211 RectTransform transform = this.transform as RectTransform;
212 float width = (transform.rect.width / segments.Length) - (SeparatorWidth * (segments.Length - 1));
213
214 for (int i = 0; i < segments.Length; i++)
215 {
216 float insetX = ((width + SeparatorWidth) * i);
217
218 var rectTransform = segments[i].GetComponent<RectTransform>();
219 rectTransform.anchorMin = Vector2.zero;
220 rectTransform.anchorMax = Vector2.zero;
221 rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, insetX, width);
222 rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, transform.rect.height);
223
224 if (separator && i > 0)
225 {
226 var sepTransform = gameObject.transform.Find("Separator " + i);
227 Graphic sep = (sepTransform != null) ? sepTransform.GetComponent<Graphic>() : (GameObject.Instantiate(separator.gameObject) as GameObject).GetComponent<Graphic>();
228 sep.gameObject.name = "Separator " + i;
229 sep.gameObject.SetActive(true);
230 sep.rectTransform.SetParent(this.transform, false);
231 sep.rectTransform.anchorMin = Vector2.zero;
232 sep.rectTransform.anchorMax = Vector2.zero;
233 sep.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, insetX - SeparatorWidth, SeparatorWidth);
234 sep.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, transform.rect.height);
235 }
236// TODO: maybe adjust text position
237 }
238 }
239 }
240}
Es.InkPainter.Math Math
Definition: PaintTest.cs:7
System.Drawing.Image Image
Definition: TestScript.cs:37
Credit Erdener Gonenc - @PixelEnvision.