Browse Source

修改bug

lzx 2 days ago
parent
commit
640af15751
100 changed files with 7572 additions and 54 deletions
  1. 42 5
      Assets/Res/UI/MainHeroPanel/BtnFaBaoWidget.prefab
  2. 155 12
      Assets/Res/UI/MainHeroPanel/MainHeroPanel.prefab
  3. 3 0
      Assets/Scripts/GameLogic/Player/FaBaoControl.cs
  4. 40 32
      Assets/Scripts/GameUI/UI/MainHeroPnael/MainHeroPanel.cs
  5. 7 5
      Assets/Scripts/GameUI/UI/MainHeroPnael/MainHeroPanelData.cs
  6. 8 0
      Assets/Scripts/GameUI/UIExtensions.meta
  7. 78 0
      Assets/Scripts/GameUI/UIExtensions/CHANGELOG.md
  8. 7 0
      Assets/Scripts/GameUI/UIExtensions/CHANGELOG.md.meta
  9. 22 0
      Assets/Scripts/GameUI/UIExtensions/LICENSE.md
  10. 7 0
      Assets/Scripts/GameUI/UIExtensions/LICENSE.md.meta
  11. 229 0
      Assets/Scripts/GameUI/UIExtensions/README.md
  12. 7 0
      Assets/Scripts/GameUI/UIExtensions/README.md.meta
  13. 9 0
      Assets/Scripts/GameUI/UIExtensions/Scripts.meta
  14. 9 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls.meta
  15. 5 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion.meta
  16. 61 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Accordion.cs
  17. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Accordion.cs.meta
  18. 218 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/AccordionElement.cs
  19. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/AccordionElement.cs.meta
  20. 5 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening.meta
  21. 120 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/FloatTween.cs
  22. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/FloatTween.cs.meta
  23. 15 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/ITweenValue.cs
  24. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/ITweenValue.cs.meta
  25. 63 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/TweenRunner.cs
  26. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/TweenRunner.cs.meta
  27. 371 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/BoxSlider.cs
  28. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/BoxSlider.cs.meta
  29. 9 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker.meta
  30. 30 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorImage.cs
  31. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorImage.cs.meta
  32. 87 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorLabel.cs
  33. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorLabel.cs.meta
  34. 303 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerControl.cs
  35. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerControl.cs.meta
  36. 194 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerPresets.cs
  37. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerPresets.cs.meta
  38. 24 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerTester.cs
  39. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerTester.cs.meta
  40. 95 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSampler.cs
  41. 13 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSampler.cs.meta
  42. 93 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSlider.cs
  43. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSlider.cs.meta
  44. 231 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSliderImage.cs
  45. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSliderImage.cs.meta
  46. 17 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorValues.cs
  47. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorValues.cs.meta
  48. 9 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events.meta
  49. 9 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events/ColorChangedEvent.cs
  50. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events/ColorChangedEvent.cs.meta
  51. 6 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events/HSVChangedEvent.cs
  52. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events/HSVChangedEvent.cs.meta
  53. 206 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/HSVUtil.cs
  54. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/HSVUtil.cs.meta
  55. 101 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/HexColorField.cs
  56. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/HexColorField.cs.meta
  57. 122 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/SVBoxSlider.cs
  58. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/SVBoxSlider.cs.meta
  59. 43 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/TiltWindow.cs
  60. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/TiltWindow.cs.meta
  61. 5 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox.meta
  62. 531 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/AutoCompleteComboBox.cs
  63. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/AutoCompleteComboBox.cs.meta
  64. 348 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/ComboBox.cs
  65. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/ComboBox.cs.meta
  66. 390 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownList.cs
  67. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownList.cs.meta
  68. 26 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownListButton.cs
  69. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownListButton.cs.meta
  70. 100 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownListItem.cs
  71. 8 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownListItem.cs.meta
  72. 197 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/CooldownButton.cs
  73. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/CooldownButton.cs.meta
  74. 83 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/InputFocus.cs
  75. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/InputFocus.cs.meta
  76. 39 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/MultiTouchScrollRect.cs
  77. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/MultiTouchScrollRect.cs.meta
  78. 258 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RadialSlider.cs
  79. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RadialSlider.cs.meta
  80. 604 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RangeSlider.cs
  81. 11 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RangeSlider.cs.meta
  82. 9 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList.meta
  83. 156 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableList.cs
  84. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableList.cs.meta
  85. 74 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListContent.cs
  86. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListContent.cs.meta
  87. 29 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListDebug.cs
  88. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListDebug.cs.meta
  89. 563 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListElement.cs
  90. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListElement.cs.meta
  91. 9 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels.meta
  92. 64 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/RescaleDragPanel.cs
  93. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/RescaleDragPanel.cs.meta
  94. 62 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/RescalePanel.cs
  95. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/RescalePanel.cs.meta
  96. 60 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/ResizePanel.cs
  97. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/ResizePanel.cs.meta
  98. 236 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Segment.cs
  99. 12 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Segment.cs.meta
  100. 245 0
      Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/SegmentedControl.cs

+ 42 - 5
Assets/Res/UI/MainHeroPanel/BtnFaBaoWidget.prefab

@@ -88,6 +88,8 @@ GameObject:
   - component: {fileID: 3423600382099007957}
   - component: {fileID: 6807793869742803418}
   - component: {fileID: 3581569104862614048}
+  - component: {fileID: 8343493153327066832}
+  - component: {fileID: 4972287993358098244}
   m_Layer: 0
   m_HasEditorInfo: 1
   m_Name: BtnFaBaoWidget
@@ -106,7 +108,7 @@ RectTransform:
   m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
   m_LocalPosition: {x: 0, y: 0, z: 0}
   m_LocalScale: {x: 1, y: 1, z: 1}
-  m_ConstrainProportionsScale: 0
+  m_ConstrainProportionsScale: 1
   m_Children:
   - {fileID: 5306337421226145797}
   - {fileID: 1790657340758011659}
@@ -117,7 +119,7 @@ RectTransform:
   m_AnchorMin: {x: 0, y: 1}
   m_AnchorMax: {x: 0, y: 1}
   m_AnchoredPosition: {x: 121, y: -1340.7}
-  m_SizeDelta: {x: 139, y: 173}
+  m_SizeDelta: {x: 166.8, y: 207.6}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &3423600382099007957
 CanvasRenderer:
@@ -199,6 +201,41 @@ MonoBehaviour:
     isList: 0
     ListCollectorDatas: []
   isAssetBundle: 1
+--- !u!114 &8343493153327066832
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3727712782042117659}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreLayout: 0
+  m_MinWidth: -1
+  m_MinHeight: -1
+  m_PreferredWidth: -1
+  m_PreferredHeight: -1
+  m_FlexibleWidth: -1
+  m_FlexibleHeight: -1
+  m_LayoutPriority: 1
+--- !u!114 &4972287993358098244
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3727712782042117659}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 916e98f1b982a9a4082fcc45c87b66c5, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  IsGrabbable: 1
+  _isTransferable: 1
+  isDroppableInSpace: 0
 --- !u!1 &7055209374934089222
 GameObject:
   m_ObjectHideFlags: 0
@@ -226,8 +263,8 @@ RectTransform:
   m_GameObject: {fileID: 7055209374934089222}
   m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
   m_LocalPosition: {x: 0, y: 0, z: 0}
-  m_LocalScale: {x: 1, y: 1, z: 1}
-  m_ConstrainProportionsScale: 0
+  m_LocalScale: {x: 1.2, y: 1.2, z: 1.2}
+  m_ConstrainProportionsScale: 1
   m_Children: []
   m_Father: {fileID: 5438064346362230487}
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -280,7 +317,7 @@ RectTransform:
   m_AnchorMin: {x: 0.5, y: 0.5}
   m_AnchorMax: {x: 0.5, y: 0.5}
   m_AnchoredPosition: {x: 0, y: 0}
-  m_SizeDelta: {x: 60, y: 72}
+  m_SizeDelta: {x: 72, y: 86.4}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &5447892676004349557
 CanvasRenderer:

+ 155 - 12
Assets/Res/UI/MainHeroPanel/MainHeroPanel.prefab

@@ -1170,7 +1170,7 @@ RectTransform:
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0.5, y: 0.5}
   m_AnchorMax: {x: 0.5, y: 0.5}
-  m_AnchoredPosition: {x: 178, y: 291}
+  m_AnchoredPosition: {x: 178, y: 291.00006}
   m_SizeDelta: {x: 361.4237, y: 549.74}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &5608414052690259127
@@ -1274,10 +1274,10 @@ RectTransform:
   m_Children: []
   m_Father: {fileID: 9037135992368401232}
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: -90}
-  m_AnchorMin: {x: 0, y: 0}
-  m_AnchorMax: {x: 1, y: 1}
-  m_AnchoredPosition: {x: 2.600006, y: 696.7}
-  m_SizeDelta: {x: -515.5, y: -824.6}
+  m_AnchorMin: {x: 0.5, y: 1}
+  m_AnchorMax: {x: 0.5, y: 1}
+  m_AnchoredPosition: {x: 2.600006, y: -115.29999}
+  m_SizeDelta: {x: 234.5, y: 799.4}
   m_Pivot: {x: 0.5, y: 0.5}
 --- !u!222 &7168131947362988611
 CanvasRenderer:
@@ -1550,7 +1550,7 @@ RectTransform:
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 90}
   m_AnchorMin: {x: 0.5, y: 0}
   m_AnchorMax: {x: 0.5, y: 0}
-  m_AnchoredPosition: {x: 0, y: 0.000061035156}
+  m_AnchoredPosition: {x: 0, y: 0}
   m_SizeDelta: {x: 399.8, y: 799.4}
   m_Pivot: {x: 0, y: 0.5}
 --- !u!222 &5209995488665193958
@@ -1814,16 +1814,16 @@ RectTransform:
   m_PrefabInstance: {fileID: 0}
   m_PrefabAsset: {fileID: 0}
   m_GameObject: {fileID: 8709778843362506203}
-  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
   m_LocalPosition: {x: 0, y: 0, z: 0}
-  m_LocalScale: {x: 1.2, y: 1.2, z: 1.2}
+  m_LocalScale: {x: 1, y: 1, z: 1}
   m_ConstrainProportionsScale: 1
   m_Children: []
-  m_Father: {fileID: 9037135992368401232}
+  m_Father: {fileID: 444754946355194245}
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0.5053333, y: 0.19325039}
   m_AnchorMax: {x: 0.5053333, y: 0.19325039}
-  m_AnchoredPosition: {x: -332.7, y: 10}
+  m_AnchoredPosition: {x: -335.1766, y: 112.984436}
   m_SizeDelta: {x: 0, y: 100}
   m_Pivot: {x: 0, y: 0.5}
 --- !u!222 &658240713667546595
@@ -1852,7 +1852,7 @@ MonoBehaviour:
     m_Top: 0
     m_Bottom: 0
   m_ChildAlignment: 0
-  m_Spacing: 0.8
+  m_Spacing: -5.8
   m_ChildForceExpandWidth: 1
   m_ChildForceExpandHeight: 1
   m_ChildControlWidth: 0
@@ -2001,9 +2001,9 @@ RectTransform:
   - {fileID: 2816985101069546935}
   - {fileID: 3568202501178809802}
   - {fileID: 600135753646096457}
+  - {fileID: 444754946355194245}
   - {fileID: 2863754501915732489}
   - {fileID: 829291352859631957}
-  - {fileID: 620873362179252296}
   m_Father: {fileID: 0}
   m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
   m_AnchorMin: {x: 0.5, y: 0.5}
@@ -2049,7 +2049,150 @@ MonoBehaviour:
     isAssetBundle: 0
     isList: 0
     ListCollectorDatas: []
+  - key: reorderableList
+    gameObject: {fileID: 1659193623004779594}
+    isAssetBundle: 0
+    isList: 0
+    ListCollectorDatas: []
   isAssetBundle: 0
+--- !u!1 &9116643901897262833
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 7
+  m_Component:
+  - component: {fileID: 444754946355194245}
+  - component: {fileID: 3881875477917835178}
+  - component: {fileID: 1659193623004779594}
+  - component: {fileID: 9141576502534239274}
+  m_Layer: 0
+  m_HasEditorInfo: 1
+  m_Name: myImage
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &444754946355194245
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9116643901897262833}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 620873362179252296}
+  m_Father: {fileID: 9037135992368401232}
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 2.9391, y: -539.1739}
+  m_SizeDelta: {x: 663.2783, y: 202.0278}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &3881875477917835178
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9116643901897262833}
+  m_CullTransparentMesh: 1
+--- !u!114 &1659193623004779594
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9116643901897262833}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 6b333d67eb08d464d823874f6a1666c2, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  ContentLayout: {fileID: 6503900326685792333}
+  DraggableArea: {fileID: 0}
+  IsDraggable: 1
+  CloneDraggedObject: 0
+  IsDropable: 1
+  IsDisplacable: 0
+  EqualizeSizesOnDrag: 0
+  maxItems: 2147483647
+  OnElementDropped:
+    m_PersistentCalls:
+      m_Calls: []
+  OnElementGrabbed:
+    m_PersistentCalls:
+      m_Calls: []
+  OnElementRemoved:
+    m_PersistentCalls:
+      m_Calls: []
+  OnElementAdded:
+    m_PersistentCalls:
+      m_Calls: []
+  OnElementDisplacedFrom:
+    m_PersistentCalls:
+      m_Calls: []
+  OnElementDisplacedTo:
+    m_PersistentCalls:
+      m_Calls: []
+  OnElementDisplacedFromReturned:
+    m_PersistentCalls:
+      m_Calls: []
+  OnElementDisplacedToReturned:
+    m_PersistentCalls:
+      m_Calls: []
+  OnElementDroppedWithMaxItems:
+    m_PersistentCalls:
+      m_Calls: []
+--- !u!114 &9141576502534239274
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 9116643901897262833}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 3c247620ca3a1fd4ab2a2f3a5b287e07, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 0.003921569}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Sprite: {fileID: 0}
+  m_Type: 0
+  m_PreserveAspect: 0
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1
+  _icon_name: 
+  isNotLoadDeftIcon: 0
+  CurrSpriteAtlas: {fileID: 0}
+  packInfo:
+    packName: 
+    packgJsonPath: 
+    packgSpritePath: 
+    lasetJsonGUID: 
+  imageH: 202.0278
+  useGradient: 0
+  topOrLeftColor: {r: 1, g: 1, b: 1, a: 1}
+  bottomOrRightColor: {r: 0, g: 0, b: 0, a: 1}
+  direction: 0
 --- !u!1001 &4255811843327571130
 PrefabInstance:
   m_ObjectHideFlags: 0

+ 3 - 0
Assets/Scripts/GameLogic/Player/FaBaoControl.cs

@@ -26,6 +26,8 @@ namespace GameLogic.Player
 
         public void ChangeUseFaBao(int index, FaBaoInfo faBaoInfo)
         {
+            if (faBaoInfo == null)
+                return;
             if (index >= 4)
             {
                 return;
@@ -54,6 +56,7 @@ namespace GameLogic.Player
                     PlayerManager.Instance.myHero.MagicWeaponID.Add(baoInfo);
                 }
             }
+
             PlayerManager.Instance.myHero.ComputeHeroInfo();
         }
     }

+ 40 - 32
Assets/Scripts/GameUI/UI/MainHeroPnael/MainHeroPanel.cs

@@ -8,6 +8,7 @@ using Fort23.UTool;
 using GameLogic.Hero;
 using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
 using UnityEngine;
+using UnityEngine.UI.Extensions;
 using Utility;
 
 namespace Fort23.Mono
@@ -55,53 +56,60 @@ namespace Fort23.Mono
         {
             Btn_Close.onClick.AddListener(() => { UIManager.Instance.HideUIUIPanel(this); });
             Btn_Sentiment.onClick.AddListener(() => { SentimentPanel.OpenPanel(); });
+
+            reorderableList.OnElementRemoved.AddListener(GetReorderableDataBegin);
+            reorderableList.OnElementDropped.AddListener(GetReorderableData);
+        }
+
+
+        public int FromIndex;
+        public int ToIndex;
+
+        private async void GetReorderableDataBegin(ReorderableList.ReorderableListEventStruct arg0)
+        {
+            FromIndex = arg0.FromIndex;
         }
 
-        private async CTask CreatHero()
+  
+        private async void GetReorderableData(ReorderableList.ReorderableListEventStruct arg0)
         {
-            modelObj = await GObjectPool.Instance.FetchAsync<GameObjectPool>(
-                PlayerManager.Instance.myHero.modelConfig.model + ".prefab", null);
-            modelObj.own.transform.parent = CameraRoot;
-            modelObj.own.transform.localEulerAngles = new Vector3(0, 167.575f, 0.118f);
-            modelObj.own.transform.localPosition = new Vector3(-4, -211, 1482);
-            modelObj.own.transform.localScale = Vector3.one * 330;
-            ChangeLayerRecursively(modelObj.own, LayerMask.NameToLayer("UiModle"));
-
-            var modelAnimComponent = modelObj.own.GetComponent<AnimancerComponent>();
-
-            int max = modelAnimComponent.Transitions.Library.Count;
-            for (int i = 0; i < max; i++)
+            ToIndex = arg0.ToIndex;
+            if (ToIndex > PlayerManager.Instance.myHero.powerUpConfig.MaxFabaoNum - 1)
             {
-                if (modelAnimComponent.Transitions.Library.TryGetTransition(i,
-                        out TransitionModifierGroup transition))
+                for (var i = 0; i < btnFaBaoWidgets.Count; i++)
                 {
-                    var modelIdleClip = transition.Transition as TransitionAsset;
-                    if (modelIdleClip != null && modelIdleClip.name == "idle")
-                    {
-                        modelAnimComponent.Play(modelIdleClip);
-                        break;
-                    }
+                    btnFaBaoWidgets[i].CustomInit(i);
                 }
-            }
-        }
 
-        public void ChangeLayerRecursively(GameObject obj, int newLayer)
-        {
-            if (obj == null || obj.layer == newLayer) return;
+                return;
+            }
 
-            // 修改当前对象的 Layer
-            obj.layer = newLayer;
+            FaBaoInfo faBaoInfo = PlayerManager.Instance.FaBaoControl.FightFaBao[FromIndex];
+            FaBaoInfo faBaoInfo1 = PlayerManager.Instance.FaBaoControl.FightFaBao[ToIndex];
+            PlayerManager.Instance.FaBaoControl.ChangeUseFaBao(FromIndex, faBaoInfo1);
+            PlayerManager.Instance.FaBaoControl.ChangeUseFaBao(ToIndex, faBaoInfo);
+            // for (var i = 0; i < btnFaBaoWidgets.Count; i++)
+            // {
+            //     btnFaBaoWidgets[i].CustomInit(i);
+            // }
+            foreach (var btnFaBaoWidget in btnFaBaoWidgets)
+            {
+                UIManager.Instance.DormancyGComponent(btnFaBaoWidget);
+            }
 
-            // 遍历所有子对象,递归修改
-            foreach (Transform child in obj.transform)
+            btnFaBaoWidgets.Clear();
+            for (int i = 0; i < 4; i++)
             {
-                ChangeLayerRecursively(child.gameObject, newLayer);
+                BtnFaBaoWidget btnFaBaoWidget =
+                    await UIManager.Instance.CreateGComponent<BtnFaBaoWidget>(null, FaBaoRoot);
+                btnFaBaoWidget.CustomInit(i);
+                btnFaBaoWidget.OnClick = OnClick;
+                btnFaBaoWidgets.Add(btnFaBaoWidget);
             }
         }
 
         public override CTask<bool> AsyncInit(object[] uiData)
         {
-            CreatHero();
             return base.AsyncInit(uiData);
         }
 

+ 7 - 5
Assets/Scripts/GameUI/UI/MainHeroPnael/MainHeroPanelData.cs

@@ -3,6 +3,8 @@ using Fort23.UTool;
 using UnityEngine.UI;
 using UnityEngine;
 using System.Collections.Generic;
+using UnityEngine.UI.Extensions;
+
 namespace Fort23.Mono
 {
 	public partial class MainHeroPanel 
@@ -63,15 +65,15 @@ namespace Fort23.Mono
 	      return _Btn_Sentiment;
 	     }
 	   }
-	  private Transform _CameraRoot;
-	  public Transform CameraRoot
+	  private ReorderableList _reorderableList;
+	  public ReorderableList reorderableList
 	   {
 	   get{
-	      if (_CameraRoot == null)
+	      if (_reorderableList == null)
 	       {
-	         _CameraRoot  = GetUIUnit<Transform>("CameraRoot"); 
+	         _reorderableList  = GetUIUnit<ReorderableList>("reorderableList"); 
 	       }
-	      return _CameraRoot;
+	      return _reorderableList;
 	     }
 	   }
 	  #endregion 自定义数据结束 

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: CClKsyquAn8pJcMYUOSCozIgu+TUyz/FtjfEjBfmYY/YicbmKS/HNffVm3GI
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 78 - 0
Assets/Scripts/GameUI/UIExtensions/CHANGELOG.md

@@ -0,0 +1,78 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/).
+
+## 2019.6 - 2.5 - Bug squash - 2021/05/10
+
+Its been a while since the last update and although Unity keeps changing, thankfully the parts underneath do not.  THanks to some awesome work by our contributors and the test teams, we made a run on some underlying bugs and issues.  If you spot anything else, please log it on the BitBucket site for resolution.
+
+> Be sure to logon to the new [Gitter Chat](https://gitter.im/Unity-UI-Extensions/Lobby) site for the UI Extensions project, if you have any questions, queries or suggestions
+>
+> Much easier that posting a question / issue on YouTube, Twitter or Facebook :D
+>
+> ## [UIExtensions Gitter Channel](https://gitter.im/Unity-UI-Extensions/Lobby)
+
+
+### Added
+
+Nothing new this time, bugfix release.
+
+### Changed
+
+- Updated UI Line connector to use relative position instead of anchored position to verify if the Lines need updating.
+- Allow menu prefabs to not have to have canvas components. This allows you to use any type of prefab as a "menu". Adam Kapos mentions the concept on the Unite talk, https://youtu.be/wbmjturGbAQ?t=1654
+- Updated segment line drawing for Line Lists. Seems Unity no longer needs UV's to be wrapped manually.
+- Updated the AutoCompleteComboBox to display text as entered (instead of all lowercase)
+- Updated the ComboBox to display text as entered (instead of all lowercase)
+- Updated ComboBox Examples to include programmatic versions
+- Further ComboBox improvements including:
+  * Upwards panel
+  * Start fixes
+  * Item Template resize
+  * Disabled sorting on combobox as it wasn't working
+  * Disabled Slider handle when not in use
+  * Updated Example
+- Updated the new Input system switch and tested against 2021
+
+### Deprecated
+
+None
+
+### Fixed
+
+- Reordering issue resolved with ScrollRectOcclusion.
+- Fixed Sorting at min and max positions for ScrollRect
+- Updated ScrollToSelect script provided by zero3growlithe, tested and vastly reduces the previous jitter. Still present but barely noticeable now.
+- Fixed Issue # 363 Update Combobox control that takes multiple items programmatically, to only allow distinct items
+- Fixed the issues where dragging outside the range slider handle causes the range to update. - Resolves #369
+- Resolves an issue with Unity putting the previous controls vertex array in an uninitialised control.
+- Applied J.R. Mitchell's fix for the Accordion Controls/Accordion/AccordionElement.cs - resolves: #364
+- Resolved issue where the Content Scroll snap issue with only 1 child. Resolves #362
+- Updated the PaginationManager to override if the ScrollSnap is in motion.
+
+### Removed
+
+None
+
+### Additional Notes
+
+#### [Installation Instructions](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted)
+
+As of Unity 2019, there are now two paths for getting access to the Unity UI Extensions project:
+
+- Unity 2019 or higher
+The recommended way to add the Unity UI Extensions project to your solution is to use the Unity package Manager. Simply use the Unity Package Manager to reference the project to install it
+
+Alternatively, you can also use the pre-compiled Unity packages if you wish, however, UPM offers full versioning support to allow you to switch versions as you wish.
+
+- Unity 2018 or lower
+The pre-compiled Unity assets are the only solution for Unity 2018 or earlier due to the changes in the Unity UI framework in Unity made for 2019.
+Either clone / download this repository to your machine and then copy the scripts in, or use the pre-packaged .UnityPackage for your version of Unity and import it as a custom package in to your project.
+
+#### Upgrade Notes
+
+Due to the restructure of the package to meet Unity's new package guidelines, we recommend **Deleting the current Unity UI Extensions** folder prior to importing the new package.
+
+For Unity 2019 users using the new UPM deployment, be sure to delete the existing folder in your assets folder before adding the new package to avoid conflict.

+ 7 - 0
Assets/Scripts/GameUI/UIExtensions/CHANGELOG.md.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 03470ebba317a0549a5582f18f4d2383
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 22 - 0
Assets/Scripts/GameUI/UIExtensions/LICENSE.md

@@ -0,0 +1,22 @@
+# Unity UI Extensions License (BSD3)
+
+Copyright (c) 2019
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
+   in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 7 - 0
Assets/Scripts/GameUI/UIExtensions/LICENSE.md.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 85fbb9f9f8b4fa3439349b9c4c495006
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 229 - 0
Assets/Scripts/GameUI/UIExtensions/README.md

@@ -0,0 +1,229 @@
+# Unity UI Extensions README
+
+This is an extension project for the new Unity UI system which can be found at: [Unity UI Source](https://bitbucket.org/Unity-Technologies/ui)
+
+> [Check out the control demos on our Tumblr page](https://unityuiextensions.tumblr.com/)
+
+## [Intro](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted)
+
+For more info, here's a little introduction video for the project:
+
+[![View Intro Video](http://img.youtube.com/vi/njoIeE4akq0/0.jpg)](http://www.youtube.com/watch?v=njoIeE4akq0 "Unity UI Extensions intro video")
+
+You can follow the UI Extensions team for updates and news on:
+
+### [Twitter](https://twitter.com/hashtag/UnityUIExtensions?src=hash) / [Facebook](https://www.facebook.com/UnityUIExtensions/) / [YouTube](https://www.youtube.com/channel/UCG3gZOkmL-2rmZat4ufv28Q)
+
+> ## Chat live with the Unity UI Extensions community on Gitter here:
+>
+> ## [UI Extensions Live Chat](https://gitter.im/Unity-UI-Extensions/Lobby)
+
+-----
+
+## [What is this repository for?](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/About)
+
+In this repository is a collection of extension scripts / effects and controls to enhance your Unity UI experience. These scripts have been gathered from many sources, combined and improved over time.
+
+> The majority of the scripts came from the Scripts thread on the [Unity UI forum here](http://bit.ly/UnityUIScriptsForumPost)
+
+You can either download / fork this project to access the scripts, or you can also download these pre-compiled Unity Assets, chock full of goodness for each release:
+
+## [Download - 2019.5 (aka 2.3)](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads)
+
+We have expanded where you can download the UnityPackage asset and widened the options to contribute to the project.
+
+> I will still stress however, ***contribution is optional***. **The assets / code will always remain FREE**
+
+| [![Download from Itch.IO](https://bytebucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/itchio.png)](https://unityuiextensions.itch.io/uiextensions2-0 "Download from Itch.IO") | [![Download from Itch.IO](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/unionassets.png)](https://unionassets.com/unity-ui-extensions "Download from Union Assets") | [![Download from Itch.IO](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/patreon.jpg)](https://www.patreon.com/UnityUIExtensions "Support Unity UI Extensions on Patreon & download")|
+| :--- | :--- | :--- |
+| [Grab from Itchio](https://unityuiextensions.itch.io/uiextensions2-0) | [Obtain via Union Assets](https://unionassets.com/unity-ui-extensions) |[Support through Patreon](https://www.patreon.com/UnityUIExtensions) |
+
+> Still available to download on the [BitBucket site](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/downloads) if you prefer
+
+To view previous releases, visit the [release archive](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads)
+
+-----
+
+## [Supporting the UI Extensions project](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=89L8T9N6BR7LJ)
+
+If you wish to further support the Unity UI Extensions project itself, then you can either subsidize your downloads above, or using the links below.
+
+All funds go to support the project, no matter the amount. **Donations in code are also extremely welcome**
+
+| | |
+|---|---|
+| [![Donate via PayPal](https://www.paypalobjects.com/webstatic/mktg/Logo/pp-logo-150px.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=89L8T9N6BR7LJ "Donating via Paypal") | [![Buy us a Coffee](https://uploads-ssl.webflow.com/5c14e387dab576fe667689cf/5cbed8a4ae2b88347c06c923_BuyMeACoffee_blue-p-500.png)](https://ko-fi.com/uiextensions "Buy us a Coffee") |
+
+> (PayPal account not required and you can remain anonymous if you wish)
+
+-----
+
+## [Getting Started](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted)
+
+To get started with the project, here's a little guide:
+
+[![View Getting Started Video](http://img.youtube.com/vi/sVLeYmsNQAI/0.jpg)](http://www.youtube.com/watch?v=sVLeYmsNQAI "Unity UI getting started video")
+
+-----
+
+## [Updates:](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/ReleaseNotes/RELEASENOTES)
+
+## Maintenance release 2019.6 - 2.5 - Bug squash
+
+Its been a while since the last update and although Unity keeps changing, thankfully the parts underneath do not.  THanks to some awesome work by our contributors and the test teams, we made a run on some underlying bugs and issues.  If you spot anything else, please log it on the BitBucket site for resolution.
+
+Be sure to also check out the "Examples" option in the Package Manager window to import the samples to your project.
+
+> Be sure to logon to the new [Gitter Chat](https://gitter.im/Unity-UI-Extensions/Lobby) site for the UI Extensions project, if you have any questions, queries or suggestions
+>
+> Much easier that posting a question / issue on YouTube, Twitter or Facebook :D
+>
+> ## [UIExtensions Gitter Channel](https://gitter.im/Unity-UI-Extensions/Lobby)
+
+### New / updated features
+
+- Updated UI Line connector to use relative position instead of anchored position to verify if the Lines need updating.
+- Allow menu prefabs to not have to have canvas components. This allows you to use any type of prefab as a "menu". Adam Kapos mentions the concept on the Unite talk, https://youtu.be/wbmjturGbAQ?t=1654
+- Updated segment line drawing for Line Lists. Seems Unity no longer needs UV's to be wrapped manually.
+- Updated the AutoCompleteComboBox to display text as entered (instead of all lowercase)
+- Updated the ComboBox to display text as entered (instead of all lowercase)
+- Updated ComboBox Examples to include programmatic versions
+- Further ComboBox improvements including:
+  * Upwards panel
+  * Start fixes
+  * Item Template resize
+  * Disabled sorting on combobox as it wasn't working
+  * Disabled Slider handle when not in use
+  * Updated Example
+- Updated the new Input system switch and tested against 2021
+
+### Examples / Examples / Examples
+
+Examples can be found either in the UPM package manager window or via the extra downloadable UnityAsset from the Bitbucket site - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads
+
+### Fixes
+
+- Reordering issue resolved with ScrollRectOcclusion.
+- Fixed Sorting at min and max positions for ScrollRect
+- Updated ScrollToSelect script provided by zero3growlithe, tested and vastly reduces the previous jitter. Still present but barely noticeable now.
+- Fixed Issue # 363 Update Combobox control that takes multiple items programmatically, to only allow distinct items
+- Fixed the issues where dragging outside the range slider handle causes the range to update. - Resolves #369
+- Resolves an issue with Unity putting the previous controls vertex array in an uninitialised control.
+- Applied J.R. Mitchell's fix for the Accordion Controls/Accordion/AccordionElement.cs - resolves: #364
+- Resolved issue where the Content Scroll snap issue with only 1 child. Resolves #362
+- Updated the PaginationManager to override if the ScrollSnap is in motion.
+
+### Known issues
+
+No new issues in this release, but check the issues list for things we are currently working on:
+
+* [UI Extensions Issue log](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues?status=new&status=open)
+
+## Upgrade Notes
+
+We recommend using the UPM delivery method. If you are using the Unity asset, there should be no issues updating but if you have a problem, just deleted the old Unity-UI-Extensions folder and import the asset new.
+
+-----
+
+## Release History
+
+For the full release history, follow the below link to the full release notes page.
+
+### [Release Notes](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/ReleaseNotes/RELEASENOTES)
+
+-----
+
+## [Controls and extensions listed in this project](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls)
+
+There are almost 70+ extension controls / effect and other utilities in the project which are listed on the following page:
+
+> ## [Check out the control demos on our Tumblr page](https://www.tumblr.com/blog/unityuiextensions)
+>
+> | [![UI Line Renderer](https://bytebucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/LineRenderer.gif)](https://www.tumblr.com/blog/unityuiextensions "UI Line Renderer") | [![UI Knob](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/UIKnob.gif)](https://www.tumblr.com/blog/unityuiextensions "UI Knob")   | [![ScrollSnap](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/ScrollSnap.gif)](https://www.tumblr.com/blog/unityuiextensions "Scroll Snap")|
+> | :--- | :--- | :--- |
+> | [UI Line Renderer](https://www.tumblr.com/blog/unityuiextensions) | [UI Knob](https://www.tumblr.com/blog/unityuiextensions) |[Scroll Snap](https://www.tumblr.com/blog/unityuiextensions) |
+
+## [UI Extensions controls list](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls)
+
+[Controls](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-controls)|||||
+------|------|------|------|------|
+Accordion|ColorPicker|Selection Box|UI Flippable|ComboBox
+AutoComplete ComboBox|DropDown List|BoundToolTip|UIWindowBase|UI Knob
+TextPic|Input Focus|Box Slider|Cooldown Button|Segmented Control
+Stepper|Range Slider|Radial Slider|MultiTouch Scroll Rect|
+||||
+
+[Primitives](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-primitives)|||||
+------|------|------|------|------|
+UILineRenderer|UILineTextureRenderer|UICircle|DiamondGraph|UICornerCut
+UIPolygon||||
+||||
+
+[Layouts](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-layouts)|||||
+------|------|------|------|------|
+Horizontal Scroll Snap|Vertical Scroll Snap|Flow Layout Group|Radial Layout|Tile Size Fitter
+Scroll Snap (alt implementation)|Reorderable List|UI Vertical Scroller|Curved Layout|Table Layout
+FancyScrollView|Card UI|Scroll Position Controller||
+||||
+
+[Effects](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-effect_components)|||||
+------|------|------|------|------|
+Best Fit Outline|Curved Text|Gradient|Gradient2|Letter Spacing
+NicerOutline|RaycastMask|UIFlippable|UIImageCrop|SoftAlphaMask
+CylinderText|UIParticleSystem|CurlyUI|Shine Effect|Shader Effects
+||||
+
+[Additional Components](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-additional_components)|||||
+------|------|------|------|------|
+ReturnKeyTrigger|TabNavigation|uGUITools|ScrollRectTweener|ScrollRectLinker
+ScrollRectEx|UI_InfiniteScroll|UI_ScrollRectOcclusion|UIScrollToSelection|UISelectableExtension
+switchToRectTransform|ScrollConflictManager|CLFZ2 (Encryption)|DragCorrector|PPIViewer
+UI_TweenScale|UI_MagneticInfiniteScroll|UI_ScrollRectOcclusion|NonDrawingGraphic|
+UILineConnector|UIHighlightable|Menu Manager|Pagination Manager|
+||||
+
+*More to come*
+
+-----
+
+## [How do I get set up?](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted)
+
+As of Unity 2019, there are now two paths for getting access to the Unity UI Extensions project:
+
+- Unity 2019 or higher
+The recommended way to add the Unity UI Extensions project to your solution is to use the Unity package Manager. Simply use the [Unity Package Manager](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/UPMInstallation) to reference the project and install it.
+
+Alternatively, you can also use the pre-compiled Unity packages if you wish, however, UPM offers full versioning support to allow you to switch versions as you wish.
+
+- Unity 2018 or lower
+The pre-compiled Unity assets are the only solution for Unity 2018 or earlier due to the changes in the Unity UI framework in Unity made for 2019.
+Either clone / download this repository to your machine and then copy the scripts in, or use the pre-packaged .UnityPackage for your version of Unity and import it as a custom package in to your project.
+
+## [Contribution guidelines](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/ContributionGuidelines)
+
+Got a script you want added? Then just fork the bitbucket repository and submit a PR.  All contributions accepted (including fixes)
+
+Just ensure:
+
+* The header of the script should match the standard used in all scripts.
+* The script uses the **Unity.UI.Extensions** namespace so they do not affect any other developments.
+* (optional) Add Component and Editor options where possible. (editor options are in the Editor\UIExtensionsMenuOptions.cs file)
+
+## [License](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/License)
+
+All scripts conform to the BSD3 license and are free to use / distribute.  See the [LICENSE](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/License) file for more information =
+
+## [Like what you see?](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/FurtherInfo)
+
+All these scripts were put together for my latest book Unity3D UI Essentials
+Check out the [page on my blog](http://bit.ly/Unity3DUIEssentials) for more details and learn all about the inner workings of the new Unity UI System.
+
+## [The downloads](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads)
+
+As this repo was created to support my new Unity UI Title ["Unity 3D UI Essentials"](http://bit.ly/Unity3DUIEssentials), in the downloads section you will find two custom assets (SpaceShip-DemoScene-Start.unitypackage and RollABallSample-Start.unitypackage).  These are just here as starter scenes for doing UI tasks in the book.
+
+I will add more sample scenes for the UI examples in this repository and detail them above over time.
+
+## [Previous Releases](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads)
+
+Please see the [full downloads list](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads) for all previous releases and their corresponding download links.

+ 7 - 0
Assets/Scripts/GameUI/UIExtensions/README.md.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: d3d1b86f715775647bde436195bbfaf0
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 9d40233b1c5add641bb2f4f7f12af05e
+folderAsset: yes
+timeCreated: 1438724032
+licenseType: Free
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: fab8c1b6e538fad489513f03e0418451
+folderAsset: yes
+timeCreated: 1468775610
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 5 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion.meta

@@ -0,0 +1,5 @@
+fileFormatVersion: 2
+guid: 82ea50ac9a6ea8940a71f86ea8d13bf0
+folderAsset: yes
+DefaultImporter:
+  userData: 

+ 61 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Accordion.cs

@@ -0,0 +1,61 @@
+///Credit ChoMPHi
+///Sourced from - http://forum.unity3d.com/threads/accordion-type-layout.271818/
+
+
+namespace UnityEngine.UI.Extensions
+{
+    [RequireComponent(typeof(HorizontalOrVerticalLayoutGroup), typeof(ContentSizeFitter), typeof(ToggleGroup))]
+	[AddComponentMenu("UI/Extensions/Accordion/Accordion Group")]
+	public class Accordion : MonoBehaviour
+	{
+		private bool m_expandVertical = true;
+		[HideInInspector]
+		public bool ExpandVerticval => m_expandVertical;
+
+		public enum Transition
+		{
+			Instant,
+			Tween
+		}
+		
+		[SerializeField] private Transition m_Transition = Transition.Instant;
+		[SerializeField] private float m_TransitionDuration = 0.3f;
+		
+		/// <summary>
+		/// Gets or sets the transition.
+		/// </summary>
+		/// <value>The transition.</value>
+		public Transition transition
+		{
+			get { return this.m_Transition; }
+			set { this.m_Transition = value; }
+		}
+		
+		/// <summary>
+		/// Gets or sets the duration of the transition.
+		/// </summary>
+		/// <value>The duration of the transition.</value>
+		public float transitionDuration
+		{
+			get { return this.m_TransitionDuration; }
+			set { this.m_TransitionDuration = value; }
+		}
+
+        private void Awake()
+        {
+			m_expandVertical = GetComponent<HorizontalLayoutGroup>() ? false : true;
+			var group = GetComponent<ToggleGroup>();
+		}
+
+#if UNITY_EDITOR
+
+        private void OnValidate()
+        {
+            if (!GetComponent<HorizontalLayoutGroup>() && !GetComponent<VerticalLayoutGroup>())
+            {
+				Debug.LogError("Accordion requires either a Horizontal or Vertical Layout group to place children");
+            }
+        }
+#endif
+	}
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Accordion.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4387cc9950f37044c92f9d144a2b1002
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 218 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/AccordionElement.cs

@@ -0,0 +1,218 @@
+///Credit ChoMPHi
+///Sourced from - http://forum.unity3d.com/threads/accordion-type-layout.271818/
+
+using System;
+using UnityEngine.UI.Extensions.Tweens;
+
+namespace UnityEngine.UI.Extensions
+{
+    [RequireComponent(typeof(RectTransform), typeof(LayoutElement))]
+	[AddComponentMenu("UI/Extensions/Accordion/Accordion Element")]
+	public class AccordionElement : Toggle
+	{
+
+		[SerializeField] private float m_MinHeight = 18f;
+
+		public float MinHeight => m_MinHeight;
+
+		[SerializeField] private float m_MinWidth = 40f;
+
+		public float MinWidth => m_MinWidth;
+
+		private Accordion m_Accordion;
+		private RectTransform m_RectTransform;
+		private LayoutElement m_LayoutElement;
+		
+		[NonSerialized]
+		private readonly TweenRunner<FloatTween> m_FloatTweenRunner;
+		
+		protected AccordionElement()
+		{
+			if (this.m_FloatTweenRunner == null)
+				this.m_FloatTweenRunner = new TweenRunner<FloatTween>();
+			
+			this.m_FloatTweenRunner.Init(this);
+		}
+		
+		protected override void Awake()
+		{
+			base.Awake();
+			base.transition = Transition.None;
+			base.toggleTransition = ToggleTransition.None;
+			this.m_Accordion = this.gameObject.GetComponentInParent<Accordion>();
+			this.m_RectTransform = this.transform as RectTransform;
+			this.m_LayoutElement = this.gameObject.GetComponent<LayoutElement>();
+			this.onValueChanged.AddListener(OnValueChanged);
+		}
+
+#if UNITY_EDITOR
+		protected override void OnValidate()
+		{
+			base.OnValidate();
+			this.m_Accordion = this.gameObject.GetComponentInParent<Accordion>();
+
+			if (this.group == null)
+			{
+				ToggleGroup tg = this.GetComponentInParent<ToggleGroup>();
+				
+				if (tg != null)
+				{
+					this.group = tg;
+				}
+			}
+			
+			LayoutElement le = this.gameObject.GetComponent<LayoutElement>();
+
+			if (le != null && m_Accordion != null)
+			{
+				if (this.isOn)
+				{
+                    if (m_Accordion.ExpandVerticval)
+                    {
+						le.preferredHeight = -1f;
+					}
+                    else
+                    {
+						le.preferredWidth = -1f;
+                    }
+				}
+				else
+				{
+					if (m_Accordion.ExpandVerticval)
+					{
+						le.preferredHeight = this.m_MinHeight;
+					}
+                    else
+                    {
+						le.preferredWidth = this.m_MinWidth;
+
+					}
+				}
+			}
+		}
+#endif
+
+		public void OnValueChanged(bool state)
+		{
+			if (this.m_LayoutElement == null)
+				return;
+			
+			Accordion.Transition transition = (this.m_Accordion != null) ? this.m_Accordion.transition : Accordion.Transition.Instant;
+
+			if (transition == Accordion.Transition.Instant && m_Accordion != null)
+			{
+				if (state)
+				{
+					if (m_Accordion.ExpandVerticval)
+					{
+						this.m_LayoutElement.preferredHeight = -1f;
+					}
+                    else
+                    {
+						this.m_LayoutElement.preferredWidth = -1f;
+					}
+				}
+				else
+				{
+					if (m_Accordion.ExpandVerticval)
+					{
+						this.m_LayoutElement.preferredHeight = this.m_MinHeight;
+					}
+                    else
+                    {
+						this.m_LayoutElement.preferredWidth = this.m_MinWidth;
+					}
+				}
+			}
+			else if (transition == Accordion.Transition.Tween)
+			{
+				if (state)
+				{
+					if (m_Accordion.ExpandVerticval)
+					{
+						this.StartTween(this.m_MinHeight, this.GetExpandedHeight());
+					}
+                    else
+                    {
+						this.StartTween(this.m_MinWidth, this.GetExpandedWidth());
+					}
+				}
+				else
+				{
+					if (m_Accordion.ExpandVerticval)
+					{
+						this.StartTween(this.m_RectTransform.rect.height, this.m_MinHeight);
+					}
+                    else
+                    {
+						this.StartTween(this.m_RectTransform.rect.width, this.m_MinWidth);
+					}
+				}
+			}
+		}
+		
+		protected float GetExpandedHeight()
+		{
+			if (this.m_LayoutElement == null)
+				return this.m_MinHeight;
+			
+			float originalPrefH = this.m_LayoutElement.preferredHeight;
+			this.m_LayoutElement.preferredHeight = -1f;
+			float h = LayoutUtility.GetPreferredHeight(this.m_RectTransform);
+			this.m_LayoutElement.preferredHeight = originalPrefH;
+			
+			return h;
+		}
+
+		protected float GetExpandedWidth()
+		{
+			if (this.m_LayoutElement == null)
+				return this.m_MinWidth;
+
+			float originalPrefW = this.m_LayoutElement.preferredWidth;
+			this.m_LayoutElement.preferredWidth = -1f;
+			float w = LayoutUtility.GetPreferredWidth(this.m_RectTransform);
+			this.m_LayoutElement.preferredWidth = originalPrefW;
+
+			return w;
+		}
+
+		protected void StartTween(float startFloat, float targetFloat)
+		{
+			float duration = (this.m_Accordion != null) ? this.m_Accordion.transitionDuration : 0.3f;
+			
+			FloatTween info = new FloatTween
+			{
+				duration = duration,
+				startFloat = startFloat,
+				targetFloat = targetFloat
+			};
+			if (m_Accordion.ExpandVerticval)
+			{
+				info.AddOnChangedCallback(SetHeight);
+			}
+            else
+            {
+				info.AddOnChangedCallback(SetWidth);
+			}
+			info.ignoreTimeScale = true;
+			this.m_FloatTweenRunner.StartTween(info);
+		}
+		
+		protected void SetHeight(float height)
+		{
+			if (this.m_LayoutElement == null)
+				return;
+				
+			this.m_LayoutElement.preferredHeight = height;
+		}
+
+		protected void SetWidth(float width)
+		{
+			if (this.m_LayoutElement == null)
+				return;
+
+			this.m_LayoutElement.preferredWidth = width;
+		}
+	}
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/AccordionElement.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3c9d341c4bc7de548937508e6f837144
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 5 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening.meta

@@ -0,0 +1,5 @@
+fileFormatVersion: 2
+guid: b9115417252d4cd42a5e167bdc1c2d3b
+folderAsset: yes
+DefaultImporter:
+  userData: 

+ 120 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/FloatTween.cs

@@ -0,0 +1,120 @@
+///Credit ChoMPHi
+///Sourced from - http://forum.unity3d.com/threads/accordion-type-layout.271818/
+
+using UnityEngine.Events;
+
+namespace UnityEngine.UI.Extensions.Tweens
+{
+    public struct FloatTween : ITweenValue
+	{
+		public class FloatTweenCallback : UnityEvent<float> {}
+		public class FloatFinishCallback : UnityEvent {}
+		
+		private float m_StartFloat;
+		private float m_TargetFloat;
+		private float m_Duration;
+		private bool m_IgnoreTimeScale;
+		private FloatTweenCallback m_Target;
+		private FloatFinishCallback m_Finish;
+		
+		/// <summary>
+		/// Gets or sets the starting float.
+		/// </summary>
+		/// <value>The start float.</value>
+		public float startFloat
+		{
+			get { return m_StartFloat; }
+			set { m_StartFloat = value; }
+		}
+		
+		/// <summary>
+		/// Gets or sets the target float.
+		/// </summary>
+		/// <value>The target float.</value>
+		public float targetFloat
+		{
+			get { return m_TargetFloat; }
+			set { m_TargetFloat = value; }
+		}
+		
+		/// <summary>
+		/// Gets or sets the duration of the tween.
+		/// </summary>
+		/// <value>The duration.</value>
+		public float duration
+		{
+			get { return m_Duration; }
+			set { m_Duration = value; }
+		}
+		
+		/// <summary>
+		/// Gets or sets a value indicating whether this <see cref="UnityEngine.UI.Tweens.ColorTween"/> should ignore time scale.
+		/// </summary>
+		/// <value><c>true</c> if ignore time scale; otherwise, <c>false</c>.</value>
+		public bool ignoreTimeScale
+		{
+			get { return m_IgnoreTimeScale; }
+			set { m_IgnoreTimeScale = value; }
+		}
+
+		/// <summary>
+		/// Tweens the float based on percentage.
+		/// </summary>
+		/// <param name="floatPercentage">Float percentage.</param>
+		public void TweenValue(float floatPercentage)
+		{
+			if (!ValidTarget())
+				return;
+			
+			m_Target.Invoke( Mathf.Lerp (m_StartFloat, m_TargetFloat, floatPercentage) );
+		}
+		
+		/// <summary>
+		/// Adds a on changed callback.
+		/// </summary>
+		/// <param name="callback">Callback.</param>
+		public void AddOnChangedCallback(UnityAction<float> callback)
+		{
+			if (m_Target == null)
+				m_Target = new FloatTweenCallback();
+			
+			m_Target.AddListener(callback);
+		}
+		
+		/// <summary>
+		/// Adds a on finish callback.
+		/// </summary>
+		/// <param name="callback">Callback.</param>
+		public void AddOnFinishCallback(UnityAction callback)
+		{
+			if (m_Finish == null)
+				m_Finish = new FloatFinishCallback();
+			
+			m_Finish.AddListener(callback);
+		}
+		
+		public bool GetIgnoreTimescale()
+		{
+			return m_IgnoreTimeScale;
+		}
+		
+		public float GetDuration()
+		{
+			return m_Duration;
+		}
+		
+		public bool ValidTarget()
+		{
+			return m_Target != null;
+		}
+		
+		/// <summary>
+		/// Invokes the on finish callback.
+		/// </summary>
+		public void Finished()
+		{
+			if (m_Finish != null)
+				m_Finish.Invoke();
+		}
+	}
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/FloatTween.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e28e1e9e18f7daa4db5d1ac279d6ce66
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 15 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/ITweenValue.cs

@@ -0,0 +1,15 @@
+///Credit ChoMPHi
+///Sourced from - http://forum.unity3d.com/threads/accordion-type-layout.271818/
+
+
+namespace UnityEngine.UI.Extensions.Tweens
+{
+    internal interface ITweenValue
+	{
+		void TweenValue(float floatPercentage);
+		bool ignoreTimeScale { get; }
+		float duration { get; }
+		bool ValidTarget();
+		void Finished();
+	}
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/ITweenValue.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9edf9da4c14ad2843879a2331b00f738
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 63 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/TweenRunner.cs

@@ -0,0 +1,63 @@
+///Credit ChoMPHi
+///Sourced from - http://forum.unity3d.com/threads/accordion-type-layout.271818/
+
+using System.Collections;
+
+namespace UnityEngine.UI.Extensions.Tweens
+{
+    // Tween runner, executes the given tween.
+    // The coroutine will live within the given 
+    // behaviour container.
+    internal class TweenRunner<T> where T : struct, ITweenValue
+	{
+		protected MonoBehaviour m_CoroutineContainer;
+		protected IEnumerator m_Tween;
+		
+		// utility function for starting the tween
+		private static IEnumerator Start(T tweenInfo)
+		{
+			if (!tweenInfo.ValidTarget())
+				yield break;
+			
+			float elapsedTime = 0.0f;
+			while (elapsedTime < tweenInfo.duration)
+			{
+				elapsedTime += tweenInfo.ignoreTimeScale ? Time.unscaledDeltaTime : Time.deltaTime;
+				var percentage = Mathf.Clamp01 (elapsedTime / tweenInfo.duration);
+				tweenInfo.TweenValue (percentage);
+				yield return null;
+			}
+			tweenInfo.TweenValue (1.0f);
+			tweenInfo.Finished();
+		}
+		
+		public void Init(MonoBehaviour coroutineContainer)
+		{
+			m_CoroutineContainer = coroutineContainer;
+		}
+		
+		public void StartTween(T info)
+		{
+			if (m_CoroutineContainer == null)
+			{
+				Debug.LogWarning ("Coroutine container not configured... did you forget to call Init?");
+				return;
+			}
+			
+			if (m_Tween != null)
+			{
+				m_CoroutineContainer.StopCoroutine (m_Tween);
+				m_Tween = null;
+			}
+			
+			if (!m_CoroutineContainer.gameObject.activeInHierarchy)
+			{
+				info.TweenValue(1.0f);
+				return;
+			}
+			
+			m_Tween = Start (info);
+			m_CoroutineContainer.StartCoroutine (m_Tween);
+		}
+	}
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Accordion/Tweening/TweenRunner.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d00ab96853b24074cb837ee70f07dddc
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 371 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/BoxSlider.cs

@@ -0,0 +1,371 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+using System;
+using UnityEngine.Events;
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    [RequireComponent(typeof(RectTransform))]
+    [AddComponentMenu("UI/Extensions/BoxSlider")]
+    public class BoxSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
+    {
+        public enum Direction
+        {
+            LeftToRight,
+            RightToLeft,
+            BottomToTop,
+            TopToBottom,
+        }
+
+        [Serializable]
+        public class BoxSliderEvent : UnityEvent<float, float> { }
+
+        [SerializeField]
+        private RectTransform m_HandleRect;
+        public RectTransform HandleRect { get { return m_HandleRect; } set { if (SetClass(ref m_HandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
+
+        [Space(6)]
+
+        [SerializeField]
+        private float m_MinValue = 0;
+        public float MinValue { get { return m_MinValue; } set { if (SetStruct(ref m_MinValue, value)) { SetX(m_ValueX); SetY(m_ValueY); UpdateVisuals(); } } }
+
+        [SerializeField]
+        private float m_MaxValue = 1;
+        public float MaxValue { get { return m_MaxValue; } set { if (SetStruct(ref m_MaxValue, value)) { SetX(m_ValueX); SetY(m_ValueY); UpdateVisuals(); } } }
+
+        [SerializeField]
+        private bool m_WholeNumbers = false;
+        public bool WholeNumbers { get { return m_WholeNumbers; } set { if (SetStruct(ref m_WholeNumbers, value)) { SetX(m_ValueX); SetY(m_ValueY); UpdateVisuals(); } } }
+
+        [SerializeField]
+        private float m_ValueX = 1f;
+        public float ValueX
+        {
+            get
+            {
+                if (WholeNumbers)
+                    return Mathf.Round(m_ValueX);
+                return m_ValueX;
+            }
+            set
+            {
+                SetX(value);
+            }
+        }
+
+        public float NormalizedValueX
+        {
+            get
+            {
+                if (Mathf.Approximately(MinValue, MaxValue))
+                    return 0;
+                return Mathf.InverseLerp(MinValue, MaxValue, ValueX);
+            }
+            set
+            {
+                this.ValueX = Mathf.Lerp(MinValue, MaxValue, value);
+            }
+        }
+
+        [SerializeField]
+        private float m_ValueY = 1f;
+        public float ValueY
+        {
+            get
+            {
+                if (WholeNumbers)
+                    return Mathf.Round(m_ValueY);
+                return m_ValueY;
+            }
+            set
+            {
+                SetY(value);
+            }
+        }
+
+        public float NormalizedValueY
+        {
+            get
+            {
+                if (Mathf.Approximately(MinValue, MaxValue))
+                    return 0;
+                return Mathf.InverseLerp(MinValue, MaxValue, ValueY);
+            }
+            set
+            {
+                this.ValueY = Mathf.Lerp(MinValue, MaxValue, value);
+            }
+        }
+
+        [Space(6)]
+
+        // Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers.
+        [SerializeField]
+        private BoxSliderEvent m_OnValueChanged = new BoxSliderEvent();
+        public BoxSliderEvent OnValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
+
+        // Private fields
+
+        private Transform m_HandleTransform;
+        private RectTransform m_HandleContainerRect;
+
+        // The offset from handle position to mouse down position
+        private Vector2 m_Offset = Vector2.zero;
+
+        private DrivenRectTransformTracker m_Tracker;
+
+        // Size of each step.
+        float StepSize { get { return WholeNumbers ? 1 : (MaxValue - MinValue) * 0.1f; } }
+
+        protected BoxSlider()
+        { }
+
+#if UNITY_EDITOR
+        protected override void OnValidate()
+        {
+            base.OnValidate();
+
+            if (WholeNumbers)
+            {
+                m_MinValue = Mathf.Round(m_MinValue);
+                m_MaxValue = Mathf.Round(m_MaxValue);
+            }
+            UpdateCachedReferences();
+            SetX(m_ValueX, false);
+            SetY(m_ValueY, false);
+            // Update rects since other things might affect them even if value didn't change.
+            if(!Application.isPlaying) UpdateVisuals();
+
+#if UNITY_2018_3_OR_NEWER
+            if (!Application.isPlaying)
+#else
+            var prefabType = UnityEditor.PrefabUtility.GetPrefabType(this);
+            if (prefabType != UnityEditor.PrefabType.Prefab && !Application.isPlaying)
+#endif
+            {
+                CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
+            }
+        }
+
+#endif // if UNITY_EDITOR
+
+        public virtual void Rebuild(CanvasUpdate executing)
+        {
+#if UNITY_EDITOR
+            if (executing == CanvasUpdate.Prelayout)
+                OnValueChanged.Invoke(ValueX, ValueY);
+#endif
+        }
+
+        public void LayoutComplete()
+        {
+
+        }
+
+        public void GraphicUpdateComplete()
+        {
+
+        }
+
+        public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
+        {
+            if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
+                return false;
+
+            currentValue = newValue;
+            return true;
+        }
+
+        public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
+        {
+            if (currentValue.Equals(newValue))
+                return false;
+
+            currentValue = newValue;
+            return true;
+        }
+
+        protected override void OnEnable()
+        {
+            base.OnEnable();
+            UpdateCachedReferences();
+            SetX(m_ValueX, false);
+            SetY(m_ValueY, false);
+            // Update rects since they need to be initialized correctly.
+            UpdateVisuals();
+        }
+
+        protected override void OnDisable()
+        {
+            m_Tracker.Clear();
+            base.OnDisable();
+        }
+
+        void UpdateCachedReferences()
+        {
+
+            if (m_HandleRect)
+            {
+                m_HandleTransform = m_HandleRect.transform;
+                if (m_HandleTransform.parent != null)
+                    m_HandleContainerRect = m_HandleTransform.parent.GetComponent<RectTransform>();
+            }
+            else
+            {
+                m_HandleContainerRect = null;
+            }
+        }
+
+        // Set the valueUpdate the visible Image.
+        void SetX(float input)
+        {
+            SetX(input, true);
+        }
+
+        void SetX(float input, bool sendCallback)
+        {
+            // Clamp the input
+            float newValue = Mathf.Clamp(input, MinValue, MaxValue);
+            if (WholeNumbers)
+                newValue = Mathf.Round(newValue);
+
+            // If the stepped value doesn't match the last one, it's time to update
+            if (m_ValueX == newValue)
+                return;
+
+            m_ValueX = newValue;
+            UpdateVisuals();
+            if (sendCallback)
+                m_OnValueChanged.Invoke(newValue, ValueY);
+        }
+
+        void SetY(float input)
+        {
+            SetY(input, true);
+        }
+
+        void SetY(float input, bool sendCallback)
+        {
+            // Clamp the input
+            float newValue = Mathf.Clamp(input, MinValue, MaxValue);
+            if (WholeNumbers)
+                newValue = Mathf.Round(newValue);
+
+            // If the stepped value doesn't match the last one, it's time to update
+            if (m_ValueY == newValue)
+                return;
+
+            m_ValueY = newValue;
+            UpdateVisuals();
+            if (sendCallback)
+                m_OnValueChanged.Invoke(ValueX, newValue);
+        }
+
+
+        protected override void OnRectTransformDimensionsChange()
+        {
+            base.OnRectTransformDimensionsChange();
+            UpdateVisuals();
+        }
+
+        enum Axis
+        {
+            Horizontal = 0,
+            Vertical = 1
+        }
+
+
+        // Force-update the slider. Useful if you've changed the properties and want it to update visually.
+        private void UpdateVisuals()
+        {
+#if UNITY_EDITOR
+            if (!Application.isPlaying)
+                UpdateCachedReferences();
+#endif
+
+            m_Tracker.Clear();
+
+
+            //to business!
+            if (m_HandleContainerRect != null)
+            {
+                m_Tracker.Add(this, m_HandleRect, DrivenTransformProperties.Anchors);
+                Vector2 anchorMin = Vector2.zero;
+                Vector2 anchorMax = Vector2.one;
+                anchorMin[0] = anchorMax[0] = (NormalizedValueX);
+                anchorMin[1] = anchorMax[1] = (NormalizedValueY);
+
+                if (Application.isPlaying)
+                {
+                    m_HandleRect.anchorMin = anchorMin;
+                    m_HandleRect.anchorMax = anchorMax;
+                }
+
+            }
+        }
+
+        // Update the slider's position based on the mouse.
+        void UpdateDrag(PointerEventData eventData, Camera cam)
+        {
+            RectTransform clickRect = m_HandleContainerRect;
+            if (clickRect != null && clickRect.rect.size[0] > 0)
+            {
+                Vector2 localCursor;
+                if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
+                    return;
+                localCursor -= clickRect.rect.position;
+
+                float val = Mathf.Clamp01((localCursor - m_Offset)[0] / clickRect.rect.size[0]);
+                NormalizedValueX = (val);
+
+                float valY = Mathf.Clamp01((localCursor - m_Offset)[1] / clickRect.rect.size[1]);
+                NormalizedValueY = (valY);
+
+            }
+        }
+
+        private bool CanDrag(PointerEventData eventData)
+        {
+            return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
+        }
+
+        public override void OnPointerDown(PointerEventData eventData)
+        {
+            if (!CanDrag(eventData))
+                return;
+
+            base.OnPointerDown(eventData);
+
+            m_Offset = Vector2.zero;
+            if (m_HandleContainerRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position, eventData.enterEventCamera))
+            {
+                Vector2 localMousePos;
+                if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
+                    m_Offset = localMousePos;
+                m_Offset.y = -m_Offset.y;
+            }
+            else
+            {
+                // Outside the slider handle - jump to this point instead
+                UpdateDrag(eventData, eventData.pressEventCamera);
+            }
+        }
+
+        public virtual void OnDrag(PointerEventData eventData)
+        {
+            if (!CanDrag(eventData))
+                return;
+
+            UpdateDrag(eventData, eventData.pressEventCamera);
+        }
+
+        public virtual void OnInitializePotentialDrag(PointerEventData eventData)
+        {
+            eventData.useDragThreshold = false;
+        }
+
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/BoxSlider.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: a3fd655d1aa9c684d88cdfdd0da9aa34
+timeCreated: 1480011174
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 7ab63fe1b000c254ebed3937038bb01b
+folderAsset: yes
+timeCreated: 1480011199
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 30 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorImage.cs

@@ -0,0 +1,30 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+    [RequireComponent(typeof(Image))]
+public class ColorImage : MonoBehaviour
+{
+    public ColorPickerControl picker;
+
+    private Image image;
+
+    private void Awake()
+    {
+        image = GetComponent<Image>();
+        picker.onValueChanged.AddListener(ColorChanged);
+    }
+
+    private void OnDestroy()
+    {
+        picker.onValueChanged.RemoveListener(ColorChanged);
+    }
+
+    private void ColorChanged(Color newColor)
+    {
+        image.color = newColor;
+    }
+}
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorImage.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 4210a64d2ce72e9488cf2ad174e9df5b
+timeCreated: 1480011173
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 87 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorLabel.cs

@@ -0,0 +1,87 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+
+    [RequireComponent(typeof(Text))]
+public class ColorLabel : MonoBehaviour
+{
+    public ColorPickerControl picker;
+
+    public ColorValues type;
+
+    public string prefix = "R: ";
+    public float minValue = 0;
+    public float maxValue = 255;
+
+    public int precision = 0;
+
+    private Text label;
+
+    private void Awake()
+    {
+        label = GetComponent<Text>();
+
+    }
+
+    private void OnEnable()
+    {
+        if (Application.isPlaying && picker != null)
+        {
+            picker.onValueChanged.AddListener(ColorChanged);
+            picker.onHSVChanged.AddListener(HSVChanged);
+        }
+    }
+
+    private void OnDestroy()
+    {
+        if (picker != null)
+        {
+            picker.onValueChanged.RemoveListener(ColorChanged);
+            picker.onHSVChanged.RemoveListener(HSVChanged);
+        }
+    }
+
+#if UNITY_EDITOR
+    private void OnValidate()
+    {
+        label = GetComponent<Text>();
+        UpdateValue();
+    }
+#endif
+
+    private void ColorChanged(Color color)
+    {
+        UpdateValue();
+    }
+
+    private void HSVChanged(float hue, float sateration, float value)
+    {
+        UpdateValue();
+    }
+
+    private void UpdateValue()
+    {
+        if (picker == null)
+        {
+            label.text = prefix + "-";
+        }
+        else
+        {
+            float value = minValue + (picker.GetValue(type) * (maxValue - minValue));
+
+            label.text = prefix + ConvertToDisplayString(value);
+        }
+    }
+
+    private string ConvertToDisplayString(float value)
+    {
+        if (precision > 0)
+            return value.ToString("f " + precision);
+        else
+            return Mathf.FloorToInt(value).ToString();
+    }
+}
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorLabel.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b32edf53f1ae84f479c9439b4b5f5b91
+timeCreated: 1480011174
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 303 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerControl.cs

@@ -0,0 +1,303 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+using System.Collections.Generic;
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+	[ExecuteInEditMode]
+	public class ColorPickerControl : MonoBehaviour
+	{
+		private float _hue = 0;
+		private float _saturation = 0;
+		private float _brightness = 0;
+
+		private float _red = 0;
+		private float _green = 0;
+		private float _blue = 0;
+
+		private float _alpha = 1;
+
+		public ColorChangedEvent onValueChanged = new ColorChangedEvent();
+		public HSVChangedEvent onHSVChanged = new HSVChangedEvent();
+
+		[SerializeField]
+		bool hsvSlidersOn = true;
+
+		[SerializeField]
+		List<GameObject> hsvSliders = new List<GameObject>();
+
+		[SerializeField]
+		bool rgbSlidersOn = true;
+
+		[SerializeField]
+		List<GameObject> rgbSliders = new List<GameObject>();
+
+		[SerializeField]
+		GameObject alphaSlider = null;
+
+		public void SetHSVSlidersOn(bool value)
+		{
+			hsvSlidersOn = value;
+
+			foreach (var item in hsvSliders)
+				item.SetActive(value);
+
+			if (alphaSlider)
+				alphaSlider.SetActive(hsvSlidersOn || rgbSlidersOn);
+		}
+
+		public void SetRGBSlidersOn(bool value)
+		{
+			rgbSlidersOn = value;
+			foreach (var item in rgbSliders)
+				item.SetActive(value);
+
+			if (alphaSlider)
+				alphaSlider.SetActive(hsvSlidersOn || rgbSlidersOn);
+		}
+
+
+		void Update()
+		{
+#if UNITY_EDITOR
+			SetHSVSlidersOn(hsvSlidersOn);
+			SetRGBSlidersOn(rgbSlidersOn);
+#endif
+		}
+
+		public Color CurrentColor
+		{
+			get
+			{
+				return new Color(_red, _green, _blue, _alpha);
+			}
+			set
+			{
+				if (CurrentColor == value)
+					return;
+
+				_red = value.r;
+				_green = value.g;
+				_blue = value.b;
+				_alpha = value.a;
+
+				RGBChanged();
+
+				SendChangedEvent();
+			}
+		}
+
+		private void Start()
+		{
+			SendChangedEvent();
+		}
+
+		public float H
+		{
+			get
+			{
+				return _hue;
+			}
+			set
+			{
+				if (_hue == value)
+					return;
+
+				_hue = value;
+
+				HSVChanged();
+
+				SendChangedEvent();
+			}
+		}
+
+		public float S
+		{
+			get
+			{
+				return _saturation;
+			}
+			set
+			{
+				if (_saturation == value)
+					return;
+
+				_saturation = value;
+
+				HSVChanged();
+
+				SendChangedEvent();
+			}
+		}
+
+		public float V
+		{
+			get
+			{
+				return _brightness;
+			}
+			set
+			{
+				if (_brightness == value)
+					return;
+
+				_brightness = value;
+
+				HSVChanged();
+
+				SendChangedEvent();
+			}
+		}
+
+		public float R
+		{
+			get
+			{
+				return _red;
+			}
+			set
+			{
+				if (_red == value)
+					return;
+
+				_red = value;
+
+				RGBChanged();
+
+				SendChangedEvent();
+			}
+		}
+
+		public float G
+		{
+			get
+			{
+				return _green;
+			}
+			set
+			{
+				if (_green == value)
+					return;
+
+				_green = value;
+
+				RGBChanged();
+
+				SendChangedEvent();
+			}
+		}
+
+		public float B
+		{
+			get
+			{
+				return _blue;
+			}
+			set
+			{
+				if (_blue == value)
+					return;
+
+				_blue = value;
+
+				RGBChanged();
+
+				SendChangedEvent();
+			}
+		}
+
+		private float A
+		{
+			get
+			{
+				return _alpha;
+			}
+			set
+			{
+				if (_alpha == value)
+					return;
+
+				_alpha = value;
+
+				SendChangedEvent();
+			}
+		}
+
+		private void RGBChanged()
+		{
+			HsvColor color = HSVUtil.ConvertRgbToHsv(CurrentColor);
+
+			_hue = color.NormalizedH;
+			_saturation = color.NormalizedS;
+			_brightness = color.NormalizedV;
+		}
+
+		private void HSVChanged()
+		{
+			Color color = HSVUtil.ConvertHsvToRgb(_hue * 360, _saturation, _brightness, _alpha);
+
+			_red = color.r;
+			_green = color.g;
+			_blue = color.b;
+		}
+
+		private void SendChangedEvent()
+		{
+			onValueChanged.Invoke(CurrentColor);
+			onHSVChanged.Invoke(_hue, _saturation, _brightness);
+		}
+
+		public void AssignColor(ColorValues type, float value)
+		{
+			switch (type)
+			{
+				case ColorValues.R:
+					R = value;
+					break;
+				case ColorValues.G:
+					G = value;
+					break;
+				case ColorValues.B:
+					B = value;
+					break;
+				case ColorValues.A:
+					A = value;
+					break;
+				case ColorValues.Hue:
+					H = value;
+					break;
+				case ColorValues.Saturation:
+					S = value;
+					break;
+				case ColorValues.Value:
+					V = value;
+					break;
+				default:
+					break;
+			}
+		}
+
+		public float GetValue(ColorValues type)
+		{
+			switch (type)
+			{
+				case ColorValues.R:
+					return R;
+				case ColorValues.G:
+					return G;
+				case ColorValues.B:
+					return B;
+				case ColorValues.A:
+					return A;
+				case ColorValues.Hue:
+					return H;
+				case ColorValues.Saturation:
+					return S;
+				case ColorValues.Value:
+					return V;
+				default:
+					throw new System.NotImplementedException("");
+			}
+		}
+	}
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerControl.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7e448480810b55843aefa91c1ab74cd2
+timeCreated: 1483197306
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 194 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerPresets.cs

@@ -0,0 +1,194 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+using System.Collections.Generic;
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+	public class ColorPickerPresets : MonoBehaviour
+	{
+		public ColorPickerControl picker;
+
+		[SerializeField]
+		protected GameObject presetPrefab;
+
+		[SerializeField]
+		protected int maxPresets = 16;
+
+		[SerializeField]
+		protected Color[] predefinedPresets;
+
+		protected List<Color> presets = new List<Color>();
+		public Image createPresetImage;
+		public Transform createButton;
+
+		public enum SaveType { None, PlayerPrefs, JsonFile }
+		[SerializeField]
+		public SaveType saveMode = SaveType.None;
+
+		[SerializeField]
+		protected string playerPrefsKey;
+
+		public virtual string JsonFilePath
+		{
+			get { return Application.persistentDataPath + "/" + playerPrefsKey + ".json"; }
+		}
+
+		protected virtual void Reset()
+		{
+			playerPrefsKey = "colorpicker_" + GetInstanceID().ToString();
+		}
+
+		protected virtual void Awake()
+		{
+			picker.onHSVChanged.AddListener(HSVChanged);
+			picker.onValueChanged.AddListener(ColorChanged);
+			picker.CurrentColor = Color.white;
+			presetPrefab.SetActive(false);
+
+			presets.AddRange(predefinedPresets);
+			LoadPresets(saveMode);
+		}
+
+		public virtual void CreatePresetButton()
+		{
+			CreatePreset(picker.CurrentColor);
+		}
+
+		public virtual void LoadPresets(SaveType saveType)
+		{
+			string jsonData = "";
+			switch (saveType)
+			{
+				case SaveType.None:
+					break;
+				case SaveType.PlayerPrefs:
+					if (PlayerPrefs.HasKey(playerPrefsKey))
+					{
+						jsonData = PlayerPrefs.GetString(playerPrefsKey);
+					}
+					break;
+				case SaveType.JsonFile:
+					if (System.IO.File.Exists(JsonFilePath))
+					{
+						jsonData = System.IO.File.ReadAllText(JsonFilePath);
+					}
+					break;
+				default:
+					throw new System.NotImplementedException(saveType.ToString());
+			}	
+
+			if (!string.IsNullOrEmpty(jsonData))
+			{
+				try
+				{
+					var jsonColors = JsonUtility.FromJson<JsonColor>(jsonData);
+					presets.AddRange(jsonColors.GetColors());
+				}
+				catch (System.Exception e)
+				{
+					Debug.LogException(e);
+				}
+			}
+
+			foreach (var item in presets)
+			{
+				CreatePreset(item, true);
+			}
+		}
+
+		public virtual void SavePresets(SaveType saveType)
+		{
+			if (presets == null || presets.Count <= 0)
+			{
+				Debug.LogError(
+					"presets cannot be null or empty: " + (presets == null ? "NULL" : "EMPTY"));
+				return;
+			}
+
+			var jsonColor = new JsonColor();
+			jsonColor.SetColors(presets.ToArray());
+
+
+			string jsonData = JsonUtility.ToJson(jsonColor);
+
+			switch (saveType)
+			{
+				case SaveType.None:
+					Debug.LogWarning("Called SavePresets with SaveType = None...");
+					break;
+				case SaveType.PlayerPrefs:
+					PlayerPrefs.SetString(playerPrefsKey, jsonData);
+					break;
+				case SaveType.JsonFile:
+					System.IO.File.WriteAllText(JsonFilePath, jsonData);
+					//Application.OpenURL(JsonFilePath);
+					break;
+				default:
+					throw new System.NotImplementedException(saveType.ToString());
+			}
+		}
+
+		protected class JsonColor
+		{
+			public Color32[] colors;
+			public void SetColors(Color[] colorsIn)
+			{
+				this.colors = new Color32[colorsIn.Length];
+				for (int i = 0; i < colorsIn.Length; i++)
+				{
+					this.colors[i] = colorsIn[i];
+				}
+			}
+
+			public Color[] GetColors()
+			{
+				Color[] colorsOut = new Color[colors.Length];
+				for (int i = 0; i < colors.Length; i++)
+				{
+					colorsOut[i] = colors[i];
+				}
+				return colorsOut;
+			}
+		}
+
+		public virtual void CreatePreset(Color color, bool loading)
+		{
+			createButton.gameObject.SetActive(presets.Count < maxPresets);
+
+			var newPresetButton = Instantiate(presetPrefab, presetPrefab.transform.parent);
+			newPresetButton.transform.SetAsLastSibling();
+			newPresetButton.SetActive(true);
+			newPresetButton.GetComponent<Image>().color = color;
+			
+			createPresetImage.color = Color.white;
+
+			if (!loading)
+			{
+				presets.Add(color);
+				SavePresets(saveMode);
+			}
+		}
+
+		public virtual void CreatePreset(Color color)
+		{
+			CreatePreset(color, false);
+		}
+
+		public virtual void PresetSelect(Image sender)
+		{
+			picker.CurrentColor = sender.color;
+		}
+
+		protected virtual void HSVChanged(float h, float s, float v)
+		{
+			createPresetImage.color = HSVUtil.ConvertHsvToRgb(h * 360, s, v, 1);
+			//Debug.Log("hsv util color: " + createPresetImage.color);
+		}
+
+		protected virtual void ColorChanged(Color color)
+		{
+			createPresetImage.color = color;
+			//Debug.Log("color changed: " + color);
+		}
+	}
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerPresets.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 502205da447ca7a479ce5ae45e5c19d2
+timeCreated: 1480011173
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 24 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerTester.cs

@@ -0,0 +1,24 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+    public class ColorPickerTester : MonoBehaviour
+    {
+        public Renderer pickerRenderer;
+        public ColorPickerControl picker;
+
+        void Awake()
+        {
+            pickerRenderer = GetComponent<Renderer>();
+        }
+        // Use this for initialization
+        void Start()
+        {
+            picker.onValueChanged.AddListener(color =>
+            {
+                pickerRenderer.material.color = color;
+            });
+        }
+    }
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorPickerTester.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 06851a815227e5044b0e3c1bf9b3a282
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 95 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSampler.cs

@@ -0,0 +1,95 @@
+/// Credit judah4
+/// Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+/// Updated by SimonDarksideJ - Updated to use touch position rather than mouse for multi-touch
+
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+	/// <summary>
+	/// Samples colors from a screen capture. 
+	/// Warning! In the editor if you're not in Free aspect mode then 
+	/// the captured area includes the grey areas to the left and right of the game view window.
+	/// In a build this will not be an issue.
+	/// 
+	/// This does not work well with a world space UI as positioning is working with screen space.
+	/// </summary>
+	public class ColorSampler : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
+    {
+        private Vector2 m_screenPos;
+
+        [SerializeField]
+		protected Button sampler;
+        private RectTransform sampleRectTransform;
+
+		[SerializeField]
+		protected Outline samplerOutline;
+
+		protected Texture2D screenCapture;
+
+		public ColorChangedEvent oncolorSelected = new ColorChangedEvent();
+
+		protected Color color;
+
+		protected virtual void OnEnable()
+		{
+			screenCapture = ScreenCapture.CaptureScreenshotAsTexture();
+            sampleRectTransform = sampler.GetComponent<RectTransform>();
+            sampler.gameObject.SetActive(true);
+			sampler.onClick.AddListener(SelectColor);
+		}
+
+		protected virtual void OnDisable()
+		{
+			Destroy(screenCapture);
+			sampler.gameObject.SetActive(false);
+			sampler.onClick.RemoveListener(SelectColor);
+		}
+
+		protected virtual void Update()
+		{
+			if (screenCapture == null)
+				return;
+
+            sampleRectTransform.position = m_screenPos;
+            color = screenCapture.GetPixel((int)m_screenPos.x, (int)m_screenPos.y);
+		
+			HandleSamplerColoring();
+		}
+
+		protected virtual void HandleSamplerColoring()
+		{
+			sampler.image.color = color;
+
+			if (samplerOutline)
+			{
+				var c = Color.Lerp(Color.white, Color.black, color.grayscale > 0.5f ? 1 : 0);
+				c.a = samplerOutline.effectColor.a;
+				samplerOutline.effectColor = c;
+			}
+		}
+
+		protected virtual void SelectColor()
+		{
+			if (oncolorSelected != null)
+				oncolorSelected.Invoke(color);
+
+			enabled = false;
+		}
+
+        public void OnPointerDown(PointerEventData eventData)
+        {
+            m_screenPos = eventData.position;
+        }
+
+        public void OnPointerUp(PointerEventData eventData)
+        {
+            m_screenPos = Vector2.zero;
+        }
+
+        public void OnDrag(PointerEventData eventData)
+        {
+            m_screenPos = eventData.position;
+        }
+    }
+}

+ 13 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSampler.cs.meta

@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 01c80b26fb6519c4ea3f410dc08f5814
+timeCreated: 1519007668
+licenseType: Pro
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 93 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSlider.cs

@@ -0,0 +1,93 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+    /// <summary>
+    /// Displays one of the color values of aColorPicker
+    /// </summary>
+    [RequireComponent(typeof(Slider))]
+    public class ColorSlider : MonoBehaviour
+    {
+        public ColorPickerControl ColorPicker;
+
+        /// <summary>
+        /// Which value this slider can edit.
+        /// </summary>
+        public ColorValues type;
+
+        private Slider slider;
+
+        private bool listen = true;
+
+        private void Awake()
+        {
+            slider = GetComponent<Slider>();
+
+            ColorPicker.onValueChanged.AddListener(ColorChanged);
+            ColorPicker.onHSVChanged.AddListener(HSVChanged);
+            slider.onValueChanged.AddListener(SliderChanged);
+        }
+
+        private void OnDestroy()
+        {
+            ColorPicker.onValueChanged.RemoveListener(ColorChanged);
+            ColorPicker.onHSVChanged.RemoveListener(HSVChanged);
+            slider.onValueChanged.RemoveListener(SliderChanged);
+        }
+
+        private void ColorChanged(Color newColor)
+        {
+            listen = false;
+            switch (type)
+            {
+                case ColorValues.R:
+                    slider.normalizedValue = newColor.r;
+                    break;
+                case ColorValues.G:
+                    slider.normalizedValue = newColor.g;
+                    break;
+                case ColorValues.B:
+                    slider.normalizedValue = newColor.b;
+                    break;
+                case ColorValues.A:
+                    slider.normalizedValue = newColor.a;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        private void HSVChanged(float hue, float saturation, float value)
+        {
+            listen = false;
+            switch (type)
+            {
+                case ColorValues.Hue:
+                    slider.normalizedValue = hue; //1 - hue;
+                    break;
+                case ColorValues.Saturation:
+                    slider.normalizedValue = saturation;
+                    break;
+                case ColorValues.Value:
+                    slider.normalizedValue = value;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        private void SliderChanged(float newValue)
+        {
+            if (listen)
+            {
+                newValue = slider.normalizedValue;
+                //if (type == ColorValues.Hue)
+                //    newValue = 1 - newValue;
+
+                ColorPicker.AssignColor(type, newValue);
+            }
+            listen = true;
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSlider.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 91558da930270ac4a960ba03b81c836a
+timeCreated: 1480011173
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 231 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSliderImage.cs

@@ -0,0 +1,231 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+    [RequireComponent(typeof(RawImage)), ExecuteInEditMode()]
+    public class ColorSliderImage : MonoBehaviour
+    {
+        public ColorPickerControl picker;
+
+        /// <summary>
+        /// Which value this slider can edit.
+        /// </summary>
+        public ColorValues type;
+
+        public Slider.Direction direction;
+
+        private RawImage image;
+
+        private RectTransform RectTransform
+        {
+            get
+            {
+                return transform as RectTransform;
+            }
+        }
+
+        private void Awake()
+        {
+            image = GetComponent<RawImage>();
+            if (image)
+            {
+                RegenerateTexture();
+            }
+            else
+            {
+                Debug.LogWarning("Missing RawImage on object [" + name + "]");
+            }
+        }
+
+        private void OnEnable()
+        {
+            if (picker != null && Application.isPlaying)
+            {
+                picker.onValueChanged.AddListener(ColorChanged);
+                picker.onHSVChanged.AddListener(ColorChanged);
+            }
+        }
+
+        private void OnDisable()
+        {
+            if (picker != null)
+            {
+                picker.onValueChanged.RemoveListener(ColorChanged);
+                picker.onHSVChanged.RemoveListener(ColorChanged);
+            }
+        }
+
+        private void OnDestroy()
+        {
+            if (image.texture != null)
+                DestroyImmediate(image.texture);
+        }
+
+#if UNITY_EDITOR
+        private void OnValidate()
+        {
+            image = GetComponent<RawImage>();
+            if (image)
+            {
+                RegenerateTexture();
+            }
+            else
+            {
+                Debug.LogWarning("Missing RawImage on object [" + name + "]");
+            }
+        }
+#endif
+
+        private void ColorChanged(Color newColor)
+        {
+            switch (type)
+            {
+                case ColorValues.R:
+                case ColorValues.G:
+                case ColorValues.B:
+                case ColorValues.Saturation:
+                case ColorValues.Value:
+                    RegenerateTexture();
+                    break;
+                case ColorValues.A:
+                case ColorValues.Hue:
+                default:
+                    break;
+            }
+        }
+
+        private void ColorChanged(float hue, float saturation, float value)
+        {
+            switch (type)
+            {
+                case ColorValues.R:
+                case ColorValues.G:
+                case ColorValues.B:
+                case ColorValues.Saturation:
+                case ColorValues.Value:
+                    RegenerateTexture();
+                    break;
+                case ColorValues.A:
+                case ColorValues.Hue:
+                default:
+                    break;
+            }
+        }
+
+        private void RegenerateTexture()
+        {
+            if (!picker)
+            {
+                Debug.LogWarning("Missing Picker on object [" + name + "]");
+            }
+            Color32 baseColor = picker != null ? picker.CurrentColor : Color.black;
+
+            float h = picker != null ? picker.H : 0;
+            float s = picker != null ? picker.S : 0;
+            float v = picker != null ? picker.V : 0;
+
+            Texture2D texture;
+            Color32[] colors;
+
+            bool vertical = direction == Slider.Direction.BottomToTop || direction == Slider.Direction.TopToBottom;
+            bool inverted = direction == Slider.Direction.TopToBottom || direction == Slider.Direction.RightToLeft;
+
+            int size;
+            switch (type)
+            {
+                case ColorValues.R:
+                case ColorValues.G:
+                case ColorValues.B:
+                case ColorValues.A:
+                    size = 255;
+                    break;
+                case ColorValues.Hue:
+                    size = 360;
+                    break;
+                case ColorValues.Saturation:
+                case ColorValues.Value:
+                    size = 100;
+                    break;
+                default:
+                    throw new System.NotImplementedException("");
+            }
+            if (vertical)
+                texture = new Texture2D(1, size);
+            else
+                texture = new Texture2D(size, 1);
+
+            texture.hideFlags = HideFlags.DontSave;
+            colors = new Color32[size];
+
+            switch (type)
+            {
+                case ColorValues.R:
+                    for (byte i = 0; i < size; i++)
+                    {
+                        colors[inverted ? size - 1 - i : i] = new Color32(i, baseColor.g, baseColor.b, 255);
+                    }
+                    break;
+                case ColorValues.G:
+                    for (byte i = 0; i < size; i++)
+                    {
+                        colors[inverted ? size - 1 - i : i] = new Color32(baseColor.r, i, baseColor.b, 255);
+                    }
+                    break;
+                case ColorValues.B:
+                    for (byte i = 0; i < size; i++)
+                    {
+                        colors[inverted ? size - 1 - i : i] = new Color32(baseColor.r, baseColor.g, i, 255);
+                    }
+                    break;
+                case ColorValues.A:
+                    for (byte i = 0; i < size; i++)
+                    {
+                        colors[inverted ? size - 1 - i : i] = new Color32(i, i, i, 255);
+                    }
+                    break;
+                case ColorValues.Hue:
+                    for (int i = 0; i < size; i++)
+                    {
+                        colors[inverted ? size - 1 - i : i] = HSVUtil.ConvertHsvToRgb(i, 1, 1, 1);
+                    }
+                    break;
+                case ColorValues.Saturation:
+                    for (int i = 0; i < size; i++)
+                    {
+                        colors[inverted ? size - 1 - i : i] = HSVUtil.ConvertHsvToRgb(h * 360, (float)i / size, v, 1);
+                    }
+                    break;
+                case ColorValues.Value:
+                    for (int i = 0; i < size; i++)
+                    {
+                        colors[inverted ? size - 1 - i : i] = HSVUtil.ConvertHsvToRgb(h * 360, s, (float)i / size, 1);
+                    }
+                    break;
+                default:
+                    throw new System.NotImplementedException("");
+            }
+            texture.SetPixels32(colors);
+            texture.Apply();
+
+            if (image.texture != null)
+                DestroyImmediate(image.texture);
+            image.texture = texture;
+
+            switch (direction)
+            {
+                case Slider.Direction.BottomToTop:
+                case Slider.Direction.TopToBottom:
+                    image.uvRect = new Rect(0, 0, 2, 1);
+                    break;
+                case Slider.Direction.LeftToRight:
+                case Slider.Direction.RightToLeft:
+                    image.uvRect = new Rect(0, 0, 1, 2);
+                    break;
+                default:
+                    break;
+            }
+        }
+
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorSliderImage.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: cd3cce5a27f2db94fa394c4719bddecd
+timeCreated: 1480011174
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 17 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorValues.cs

@@ -0,0 +1,17 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+    public enum ColorValues
+    {
+        R,
+        G,
+        B,
+        A,
+
+        Hue,
+        Saturation,
+        Value
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/ColorValues.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 0f473590aed5e3f4ab5a0157b2a53dbd
+timeCreated: 1480011173
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: cbbc689694061e6439664eda55449513
+folderAsset: yes
+timeCreated: 1480011173
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events/ColorChangedEvent.cs

@@ -0,0 +1,9 @@
+using System;
+using UnityEngine;
+using UnityEngine.Events;
+
+[Serializable]
+public class ColorChangedEvent : UnityEvent<Color>
+{
+
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events/ColorChangedEvent.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ff46fbecea7739f4690e4285c88f53c5
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 6 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events/HSVChangedEvent.cs

@@ -0,0 +1,6 @@
+using UnityEngine.Events;
+
+public class HSVChangedEvent : UnityEvent<float, float, float>
+{
+
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/Events/HSVChangedEvent.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 3d95ce8fba3dbbf4eb14411412169b88
+timeCreated: 1442747317
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 206 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/HSVUtil.cs

@@ -0,0 +1,206 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+using System;
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+    #region ColorUtilities
+
+    public static class HSVUtil
+    {
+        public static HsvColor ConvertRgbToHsv(Color color)
+        {
+            return ConvertRgbToHsv((int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255));
+        }
+
+        //Converts an RGB color to an HSV color.
+        public static HsvColor ConvertRgbToHsv(double r, double b, double g)
+        {
+            double delta, min;
+            double h = 0, s, v;
+
+            min = Math.Min(Math.Min(r, g), b);
+            v = Math.Max(Math.Max(r, g), b);
+            delta = v - min;
+
+            if (v == 0.0)
+                s = 0;
+            else
+                s = delta / v;
+
+            if (s == 0)
+                h = 360;
+            else
+            {
+                if (r == v)
+                    h = (g - b) / delta;
+                else if (g == v)
+                    h = 2 + (b - r) / delta;
+                else if (b == v)
+                    h = 4 + (r - g) / delta;
+
+                h *= 60;
+                if (h <= 0.0)
+                    h += 360;
+            }
+
+            HsvColor hsvColor = new HsvColor()
+            {
+                H = 360 - h,
+                S = s,
+                V = v / 255
+            };
+            return hsvColor;
+
+        }
+
+        // Converts an HSV color to an RGB color.
+        public static Color ConvertHsvToRgb(double h, double s, double v, float alpha)
+        {
+
+            double r = 0, g = 0, b = 0;
+
+            if (s == 0)
+            {
+                r = v;
+                g = v;
+                b = v;
+            }
+
+            else
+            {
+                int i;
+                double f, p, q, t;
+
+
+                if (h == 360)
+                    h = 0;
+                else
+                    h = h / 60;
+
+                i = (int)(h);
+                f = h - i;
+
+                p = v * (1.0 - s);
+                q = v * (1.0 - (s * f));
+                t = v * (1.0 - (s * (1.0f - f)));
+
+
+                switch (i)
+                {
+                    case 0:
+                        r = v;
+                        g = t;
+                        b = p;
+                        break;
+
+                    case 1:
+                        r = q;
+                        g = v;
+                        b = p;
+                        break;
+
+                    case 2:
+                        r = p;
+                        g = v;
+                        b = t;
+                        break;
+
+                    case 3:
+                        r = p;
+                        g = q;
+                        b = v;
+                        break;
+
+                    case 4:
+                        r = t;
+                        g = p;
+                        b = v;
+                        break;
+
+                    default:
+                        r = v;
+                        g = p;
+                        b = q;
+                        break;
+                }
+
+            }
+
+            return new Color((float)r, (float)g, (float)b, alpha);
+
+        }
+    }
+
+    #endregion ColorUtilities
+
+    // Describes a color in terms of
+    // Hue, Saturation, and Value (brightness)
+    #region HsvColor
+    public struct HsvColor
+    {
+        /// <summary>
+        /// The Hue, ranges between 0 and 360
+        /// </summary>
+        public double H;
+
+        /// <summary>
+        /// The saturation, ranges between 0 and 1
+        /// </summary>
+        public double S;
+
+        // The value (brightness), ranges between 0 and 1
+        public double V;
+
+        public float NormalizedH
+        {
+            get
+            {
+                return (float)H / 360f;
+            }
+
+            set
+            {
+                H = (double)value * 360;
+            }
+        }
+
+        public float NormalizedS
+        {
+            get
+            {
+                return (float)S;
+            }
+            set
+            {
+                S = value;
+            }
+        }
+
+        public float NormalizedV
+        {
+            get
+            {
+                return (float)V;
+            }
+            set
+            {
+                V = (double)value;
+            }
+        }
+
+        public HsvColor(double h, double s, double v)
+        {
+            this.H = h;
+            this.S = s;
+            this.V = v;
+        }
+
+        public override string ToString()
+        {
+            return "{" + H.ToString("f2") + "," + S.ToString("f2") + "," + V.ToString("f2") + "}";
+        }
+    }
+    #endregion HsvColor
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/HSVUtil.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4f3189246d7fc204faba7a1e9c08e0af
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 101 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/HexColorField.cs

@@ -0,0 +1,101 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+using System.Globalization;
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+
+    [RequireComponent(typeof(InputField))]
+public class HexColorField : MonoBehaviour
+{
+    public ColorPickerControl ColorPicker;
+
+    public bool displayAlpha;
+
+    private InputField hexInputField;
+
+    private const string hexRegex = "^#?(?:[0-9a-fA-F]{3,4}){1,2}$";
+
+    private void Awake()
+    {
+        hexInputField = GetComponent<InputField>();
+
+        // Add listeners to keep text (and color) up to date
+        hexInputField.onEndEdit.AddListener(UpdateColor);
+        ColorPicker.onValueChanged.AddListener(UpdateHex);
+    }
+
+    private void OnDestroy()
+    {
+        hexInputField.onValueChanged.RemoveListener(UpdateColor);
+        ColorPicker.onValueChanged.RemoveListener(UpdateHex);
+    }
+
+    private void UpdateHex(Color newColor)
+    {
+        hexInputField.text = ColorToHex(newColor);
+    }
+
+    private void UpdateColor(string newHex)
+    {
+        Color32 color;
+        if (HexToColor(newHex, out color))
+            ColorPicker.CurrentColor = color;
+        else
+            Debug.Log("hex value is in the wrong format, valid formats are: #RGB, #RGBA, #RRGGBB and #RRGGBBAA (# is optional)");
+    }
+
+    private string ColorToHex(Color32 color)
+    {
+        if (displayAlpha)
+            return string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", color.r, color.g, color.b, color.a);
+        else
+            return string.Format("#{0:X2}{1:X2}{2:X2}", color.r, color.g, color.b);
+    }
+
+    public static bool HexToColor(string hex, out Color32 color)
+    {
+        // Check if this is a valid hex string (# is optional)
+        if (System.Text.RegularExpressions.Regex.IsMatch(hex, hexRegex))
+        {
+            int startIndex = hex.StartsWith("#") ? 1 : 0;
+
+            if (hex.Length == startIndex + 8) //#RRGGBBAA
+            {
+                color = new Color32(byte.Parse(hex.Substring(startIndex, 2), NumberStyles.AllowHexSpecifier),
+                    byte.Parse(hex.Substring(startIndex + 2, 2), NumberStyles.AllowHexSpecifier),
+                    byte.Parse(hex.Substring(startIndex + 4, 2), NumberStyles.AllowHexSpecifier),
+                    byte.Parse(hex.Substring(startIndex + 6, 2), NumberStyles.AllowHexSpecifier));
+            }
+            else if (hex.Length == startIndex + 6)  //#RRGGBB
+            {
+                color = new Color32(byte.Parse(hex.Substring(startIndex, 2), NumberStyles.AllowHexSpecifier),
+                    byte.Parse(hex.Substring(startIndex + 2, 2), NumberStyles.AllowHexSpecifier),
+                    byte.Parse(hex.Substring(startIndex + 4, 2), NumberStyles.AllowHexSpecifier),
+                    255);
+            }
+            else if (hex.Length == startIndex + 4) //#RGBA
+            {
+                color = new Color32(byte.Parse("" + hex[startIndex] + hex[startIndex], NumberStyles.AllowHexSpecifier),
+                    byte.Parse("" + hex[startIndex + 1] + hex[startIndex + 1], NumberStyles.AllowHexSpecifier),
+                    byte.Parse("" + hex[startIndex + 2] + hex[startIndex + 2], NumberStyles.AllowHexSpecifier),
+                    byte.Parse("" + hex[startIndex + 3] + hex[startIndex + 3], NumberStyles.AllowHexSpecifier));
+            }
+            else  //#RGB
+            {
+                color = new Color32(byte.Parse("" + hex[startIndex] + hex[startIndex], NumberStyles.AllowHexSpecifier),
+                    byte.Parse("" + hex[startIndex + 1] + hex[startIndex + 1], NumberStyles.AllowHexSpecifier),
+                    byte.Parse("" + hex[startIndex + 2] + hex[startIndex + 2], NumberStyles.AllowHexSpecifier),
+                    255);
+            }
+            return true;
+        }
+        else
+        {
+            color = new Color32();
+            return false;
+        }
+    }
+}
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/HexColorField.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7343402602909bd4f928d58433c5c87f
+timeCreated: 1480011173
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 122 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/SVBoxSlider.cs

@@ -0,0 +1,122 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+
+namespace UnityEngine.UI.Extensions.ColorPicker
+{
+    [RequireComponent(typeof(BoxSlider), typeof(RawImage)), ExecuteInEditMode()]
+    public class SVBoxSlider : MonoBehaviour
+    {
+        public ColorPickerControl picker;
+
+        private BoxSlider slider;
+        private RawImage image;
+
+        private float lastH = -1;
+        private bool listen = true;
+
+        public RectTransform RectTransform
+        {
+            get
+            {
+                return transform as RectTransform;
+            }
+        }
+
+        private void Awake()
+        {
+            slider = GetComponent<BoxSlider>();
+            image = GetComponent<RawImage>();
+
+            RegenerateSVTexture();
+        }
+
+        private void OnEnable()
+        {
+            if (Application.isPlaying && picker != null)
+            {
+                slider.OnValueChanged.AddListener(SliderChanged);
+                picker.onHSVChanged.AddListener(HSVChanged);
+            }
+        }
+
+        private void OnDisable()
+        {
+            if (picker != null)
+            {
+                slider.OnValueChanged.RemoveListener(SliderChanged);
+                picker.onHSVChanged.RemoveListener(HSVChanged);
+            }
+        }
+
+        private void OnDestroy()
+        {
+            if (image.texture != null)
+                DestroyImmediate(image.texture);
+        }
+
+#if UNITY_EDITOR
+        private void OnValidate()
+        {
+            image = GetComponent<RawImage>();
+            RegenerateSVTexture();
+        }
+#endif
+
+        private void SliderChanged(float saturation, float value)
+        {
+            if (listen)
+            {
+                picker.AssignColor(ColorValues.Saturation, saturation);
+                picker.AssignColor(ColorValues.Value, value);
+            }
+            listen = true;
+        }
+
+        private void HSVChanged(float h, float s, float v)
+        {
+            if (lastH != h)
+            {
+                lastH = h;
+                RegenerateSVTexture();
+            }
+
+            if (s != slider.NormalizedValueX)
+            {
+                listen = false;
+                slider.NormalizedValueX = s;
+            }
+
+            if (v != slider.NormalizedValueY)
+            {
+                listen = false;
+                slider.NormalizedValueY = v;
+            }
+        }
+
+        private void RegenerateSVTexture()
+        {
+            double h = picker != null ? picker.H * 360 : 0;
+
+            if (image.texture != null)
+                DestroyImmediate(image.texture);
+
+            Texture2D texture = new Texture2D(100, 100)
+            {
+                hideFlags = HideFlags.DontSave
+            };
+            for (int s = 0; s < 100; s++)
+            {
+                Color32[] colors = new Color32[100];
+                for (int v = 0; v < 100; v++)
+                {
+                    colors[v] = HSVUtil.ConvertHsvToRgb(h, (float)s / 100, (float)v / 100, 1);
+                }
+                texture.SetPixels32(s, 0, 1, 100, colors);
+            }
+            texture.Apply();
+
+            image.texture = texture;
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/SVBoxSlider.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7a0647785ed421e449239dbd6512e156
+timeCreated: 1480011173
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 43 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/TiltWindow.cs

@@ -0,0 +1,43 @@
+///Credit judah4
+///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
+
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    public class TiltWindow : MonoBehaviour, IDragHandler
+    {
+        public Vector2 range = new Vector2(5f, 3f);
+
+        private Transform mTrans;
+        private Quaternion mStart;
+        private Vector2 mRot = Vector2.zero;
+        private Vector2 m_screenPos;
+
+
+        void Start()
+        {
+            mTrans = transform;
+            mStart = mTrans.localRotation;
+        }
+
+        void Update()
+        {
+            Vector3 pos = m_screenPos;
+
+            float halfWidth = Screen.width * 0.5f;
+            float halfHeight = Screen.height * 0.5f;
+            float x = Mathf.Clamp((pos.x - halfWidth) / halfWidth, -1f, 1f);
+            float y = Mathf.Clamp((pos.y - halfHeight) / halfHeight, -1f, 1f);
+            mRot = Vector2.Lerp(mRot, new Vector2(x, y), Time.deltaTime * 5f);
+
+            mTrans.localRotation = mStart * Quaternion.Euler(-mRot.y * range.y, mRot.x * range.x, 0f);
+        }
+
+
+        public void OnDrag(PointerEventData eventData)
+        {
+            m_screenPos = eventData.position;
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ColorPicker/TiltWindow.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c7be5109ea5b91e4b856621023b15168
+timeCreated: 1480011174
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 5 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox.meta

@@ -0,0 +1,5 @@
+fileFormatVersion: 2
+guid: 726a11b8d64fa0143b34f417f5453f80
+folderAsset: yes
+DefaultImporter:
+  userData: 

+ 531 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/AutoCompleteComboBox.cs

@@ -0,0 +1,531 @@
+///Credit perchik
+///Sourced from - http://forum.unity3d.com/threads/receive-onclick-event-and-pass-it-on-to-lower-ui-elements.293642/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace UnityEngine.UI.Extensions
+{
+    public enum AutoCompleteSearchType
+    {
+        ArraySort,
+        Linq
+    }
+
+    [RequireComponent(typeof(RectTransform))]
+    [AddComponentMenu("UI/Extensions/AutoComplete ComboBox")]
+    public class AutoCompleteComboBox : MonoBehaviour
+    {
+        public Color disabledTextColor;
+        public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it
+
+        /// <summary>
+        /// Contains the included items. To add and remove items to/from this list, use the <see cref="AddItem(string)"/>,
+        /// <see cref="RemoveItem(string)"/> and <see cref="SetAvailableOptions(List{string})"/> methods as these also execute
+        /// the required methods to update to the current collection.
+        /// </summary>
+        public List<string> AvailableOptions;
+
+        //private bool isInitialized = false;
+        private bool _isPanelActive = false;
+        private bool _hasDrawnOnce = false;
+
+        private InputField _mainInput;
+        private RectTransform _inputRT;
+
+		//private Button _arrow_Button;
+
+        private RectTransform _rectTransform;
+
+        private RectTransform _overlayRT;
+        private RectTransform _scrollPanelRT;
+        private RectTransform _scrollBarRT;
+        private RectTransform _slidingAreaRT;
+        private RectTransform _scrollHandleRT;
+        private RectTransform _itemsPanelRT;
+        private Canvas _canvas;
+        private RectTransform _canvasRT;
+
+        private ScrollRect _scrollRect;
+
+        private List<string> _panelItems; //items that will get shown in the drop-down
+        private List<string> _prunedPanelItems; //items that used to show in the drop-down
+
+        private Dictionary<string, GameObject> panelObjects;
+        
+        private GameObject itemTemplate;
+
+        public string Text { get; private set; }
+
+        [SerializeField]
+        private float _scrollBarWidth = 20.0f;
+        public float ScrollBarWidth
+        {
+            get { return _scrollBarWidth; }
+            set
+            {
+                _scrollBarWidth = value;
+                RedrawPanel();
+            }
+        }
+
+        //    private int scrollOffset; //offset of the selected item
+        //    private int _selectedIndex = 0;
+
+        [SerializeField]
+        private int _itemsToDisplay;
+        public int ItemsToDisplay
+        {
+            get { return _itemsToDisplay; }
+            set
+            {
+                _itemsToDisplay = value;
+                RedrawPanel();
+            }
+        }
+
+		public bool SelectFirstItemOnStart = false;
+
+		[SerializeField]
+        [Tooltip("Change input text color based on matching items")]
+        private bool _ChangeInputTextColorBasedOnMatchingItems = false;
+		public bool InputColorMatching{
+			get { return _ChangeInputTextColorBasedOnMatchingItems; }
+			set 
+			{
+				_ChangeInputTextColorBasedOnMatchingItems = value;
+				if (_ChangeInputTextColorBasedOnMatchingItems) {
+					SetInputTextColor ();
+				}
+			}
+		}
+
+        public float DropdownOffset = 10f;
+
+        //TODO design as foldout for Inspector
+        public Color ValidSelectionTextColor = Color.green;
+		public Color MatchingItemsRemainingTextColor = Color.black;
+		public Color NoItemsRemainingTextColor = Color.red;
+
+        public AutoCompleteSearchType autocompleteSearchType = AutoCompleteSearchType.Linq;
+
+        [SerializeField]
+        private bool _displayPanelAbove = false;
+
+        private bool _selectionIsValid = false;
+
+		[System.Serializable]
+		public class SelectionChangedEvent :  UnityEngine.Events.UnityEvent<string, bool> {
+		}
+
+        [System.Serializable]
+		public class SelectionTextChangedEvent :  UnityEngine.Events.UnityEvent<string> {
+		}
+
+		[System.Serializable]
+		public class SelectionValidityChangedEvent :  UnityEngine.Events.UnityEvent<bool> {
+		}
+
+		// fires when input text is changed;
+		public SelectionTextChangedEvent OnSelectionTextChanged;
+		// fires when an Item gets selected / deselected (including when items are added/removed once this is possible)
+		public SelectionValidityChangedEvent OnSelectionValidityChanged;
+		// fires in both cases
+		public SelectionChangedEvent OnSelectionChanged;
+
+        public void Awake()
+        {
+            Initialize();
+        }
+
+		public void Start()
+		{
+			if (SelectFirstItemOnStart && AvailableOptions.Count > 0) {
+				ToggleDropdownPanel (false);
+				OnItemClicked (AvailableOptions [0]);
+			}
+            RedrawPanel();
+        }
+
+        private bool Initialize()
+        {
+            bool success = true;
+            try
+            {
+                _rectTransform = GetComponent<RectTransform>();
+                _inputRT = _rectTransform.Find("InputField").GetComponent<RectTransform>();
+                _mainInput = _inputRT.GetComponent<InputField>();
+
+				//_arrow_Button = _rectTransform.FindChild ("ArrowBtn").GetComponent<Button> ();
+
+                _overlayRT = _rectTransform.Find("Overlay").GetComponent<RectTransform>();
+                _overlayRT.gameObject.SetActive(false);
+
+
+                _scrollPanelRT = _overlayRT.Find("ScrollPanel").GetComponent<RectTransform>();
+                _scrollBarRT = _scrollPanelRT.Find("Scrollbar").GetComponent<RectTransform>();
+                _slidingAreaRT = _scrollBarRT.Find("SlidingArea").GetComponent<RectTransform>();
+                _scrollHandleRT = _slidingAreaRT.Find("Handle").GetComponent<RectTransform>();
+                _itemsPanelRT = _scrollPanelRT.Find("Items").GetComponent<RectTransform>();
+                //itemPanelLayout = itemsPanelRT.gameObject.GetComponent<LayoutGroup>();
+
+                _canvas = GetComponentInParent<Canvas>();
+                _canvasRT = _canvas.GetComponent<RectTransform>();
+
+                _scrollRect = _scrollPanelRT.GetComponent<ScrollRect>();
+                _scrollRect.scrollSensitivity = _rectTransform.sizeDelta.y / 2;
+                _scrollRect.movementType = ScrollRect.MovementType.Clamped;
+                _scrollRect.content = _itemsPanelRT;
+
+                itemTemplate = _rectTransform.Find("ItemTemplate").gameObject;
+                itemTemplate.SetActive(false);
+            }
+            catch (System.NullReferenceException ex)
+            {
+                Debug.LogException(ex);
+                Debug.LogError("Something is setup incorrectly with the dropdownlist component causing a Null Reference Exception");
+                success = false;
+            }
+            panelObjects = new Dictionary<string, GameObject>();
+
+            _prunedPanelItems = new List<string>();
+            _panelItems = new List<string>();
+
+            RebuildPanel();
+            return success;
+        }
+
+        /// <summary>
+        /// Adds the item to <see cref="this.AvailableOptions"/> if it is not a duplicate and rebuilds the panel.
+        /// </summary>
+        /// <param name="item">Item to add.</param>
+        public void AddItem(string item)
+        {
+            if (!this.AvailableOptions.Contains(item))
+            {
+                this.AvailableOptions.Add(item);
+                this.RebuildPanel();
+            }
+            else
+            {
+                Debug.LogWarning($"{nameof(AutoCompleteComboBox)}.{nameof(AddItem)}: items may only exists once. '{item}' can not be added.");
+            }
+        }
+
+        /// <summary>
+        /// Removes the item from <see cref="this.AvailableOptions"/> and rebuilds the panel.
+        /// </summary>
+        /// <param name="item">Item to remove.</param>
+        public void RemoveItem(string item)
+        {
+            if (this.AvailableOptions.Contains(item))
+            {
+                this.AvailableOptions.Remove(item);
+                this.RebuildPanel();
+            }
+        }
+
+        /// <summary>
+        /// Sets the given items as new content for the comboBox. Previous entries will be cleared.
+        /// </summary>
+        /// <param name="newOptions">New entries.</param>
+        public void SetAvailableOptions(List<string> newOptions)
+        {
+            var uniqueOptions = newOptions.Distinct().ToList();
+            if (newOptions.Count != uniqueOptions.Count)
+            {
+                Debug.LogWarning($"{nameof(AutoCompleteComboBox)}.{nameof(SetAvailableOptions)}: items may only exists once. {newOptions.Count - uniqueOptions.Count} duplicates.");
+            }
+
+            this.AvailableOptions.Clear();
+            this.AvailableOptions = uniqueOptions;
+            this.RebuildPanel();
+        }
+
+        /// <summary>
+        /// Sets the given items as new content for the comboBox. Previous entries will be cleared.
+        /// </summary>
+        /// <param name="newOptions">New entries.</param>
+        public void SetAvailableOptions(string[] newOptions)
+        {
+            var uniqueOptions = newOptions.Distinct().ToList();
+            if (newOptions.Length != uniqueOptions.Count)
+            {
+                Debug.LogWarning($"{nameof(AutoCompleteComboBox)}.{nameof(SetAvailableOptions)}: items may only exists once. {newOptions.Length - uniqueOptions.Count} duplicates.");
+            }
+
+            this.AvailableOptions.Clear();
+            for (int i = 0; i < newOptions.Length; i++)
+            {
+                this.AvailableOptions.Add(newOptions[i]);
+            }
+
+            this.RebuildPanel();
+        }
+
+        public void ResetItems()
+        {
+            AvailableOptions.Clear();
+            RebuildPanel();
+        }
+
+        /// <summary>
+        /// Rebuilds the contents of the panel in response to items being added.
+        /// </summary>
+        private void RebuildPanel()
+        {
+            if (_isPanelActive) ToggleDropdownPanel();
+
+            //panel starts with all options
+            _panelItems.Clear();
+            _prunedPanelItems.Clear();
+            panelObjects.Clear();
+
+            //clear Autocomplete children in scene
+            foreach (Transform child in _itemsPanelRT.transform)
+            {
+                Destroy(child.gameObject);
+            }
+
+            foreach (string option in AvailableOptions)
+            {
+                _panelItems.Add(option.ToLower());
+            }
+
+            List<GameObject> itemObjs = new List<GameObject>(panelObjects.Values);
+
+            int indx = 0;
+            while (itemObjs.Count < AvailableOptions.Count)
+            {
+                GameObject newItem = Instantiate(itemTemplate) as GameObject;
+                newItem.name = "Item " + indx;
+                newItem.transform.SetParent(_itemsPanelRT, false);
+                itemObjs.Add(newItem);
+                indx++;
+            }
+
+            for (int i = 0; i < itemObjs.Count; i++)
+            {
+                itemObjs[i].SetActive(i <= AvailableOptions.Count);
+                if (i < AvailableOptions.Count)
+                {
+                    itemObjs[i].name = "Item " + i + " " + _panelItems[i];
+                    itemObjs[i].transform.Find("Text").GetComponent<Text>().text = AvailableOptions[i]; //set the text value
+
+                    Button itemBtn = itemObjs[i].GetComponent<Button>();
+                    itemBtn.onClick.RemoveAllListeners();
+                    string textOfItem = _panelItems[i]; //has to be copied for anonymous function or it gets garbage collected away
+                    itemBtn.onClick.AddListener(() =>
+                    {
+                        OnItemClicked(textOfItem);
+                    });
+                    panelObjects[_panelItems[i]] = itemObjs[i];
+                }
+            }
+			SetInputTextColor ();
+        }
+
+        /// <summary>
+        /// what happens when an item in the list is selected
+        /// </summary>
+        /// <param name="item"></param>
+        private void OnItemClicked(string item)
+        {
+            //Debug.Log("item " + item + " clicked");
+            Text = item;
+            _mainInput.text = Text;
+            ToggleDropdownPanel(true);
+        }
+
+        //private void UpdateSelected()
+        //{
+        //    SelectedItem = (_selectedIndex > -1 && _selectedIndex < Items.Count) ? Items[_selectedIndex] : null;
+        //    if (SelectedItem == null) return;
+
+        //    bool hasImage = SelectedItem.Image != null;
+        //    if (hasImage)
+        //    {
+        //        mainButton.img.sprite = SelectedItem.Image;
+        //        mainButton.img.color = Color.white;
+
+        //        //if (Interactable) mainButton.img.color = Color.white;
+        //        //else mainButton.img.color = new Color(1, 1, 1, .5f);
+        //    }
+        //    else
+        //    {
+        //        mainButton.img.sprite = null;
+        //    }
+
+        //    mainButton.txt.text = SelectedItem.Caption;
+
+        //    //update selected index color
+        //    for (int i = 0; i < itemsPanelRT.childCount; i++)
+        //    {
+        //        panelItems[i].btnImg.color = (_selectedIndex == i) ? mainButton.btn.colors.highlightedColor : new Color(0, 0, 0, 0);
+        //    }
+        //}
+
+
+        private void RedrawPanel()
+        {
+            float scrollbarWidth = _panelItems.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items
+            _scrollBarRT.gameObject.SetActive(_panelItems.Count > ItemsToDisplay);
+            if (!_hasDrawnOnce || _rectTransform.sizeDelta != _inputRT.sizeDelta)
+            {
+                _hasDrawnOnce = true;
+                _inputRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
+                _inputRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _rectTransform.sizeDelta.y);
+
+                _scrollPanelRT.SetParent(transform, true);//break the scroll panel from the overlay
+                _scrollPanelRT.anchoredPosition = _displayPanelAbove ?
+                    new Vector2(0, DropdownOffset + _rectTransform.sizeDelta.y * _panelItems.Count - 1) :
+                    new Vector2(0, -_rectTransform.sizeDelta.y);
+
+                //make the overlay fill the screen
+                _overlayRT.SetParent(_canvas.transform, false); //attach it to top level object
+                _overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _canvasRT.sizeDelta.x);
+                _overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _canvasRT.sizeDelta.y);
+
+                _overlayRT.SetParent(transform, true);//reattach to this object
+                _scrollPanelRT.SetParent(_overlayRT, true); //reattach the scrollpanel to the overlay
+            }
+
+            if (_panelItems.Count < 1) return;
+
+            float dropdownHeight = _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, _panelItems.Count) + DropdownOffset;
+
+            _scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
+            _scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
+
+            _itemsPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _scrollPanelRT.sizeDelta.x - scrollbarWidth - 5);
+            _itemsPanelRT.anchoredPosition = new Vector2(5, 0);
+
+            _scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, scrollbarWidth);
+            _scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
+            if (scrollbarWidth == 0) _scrollHandleRT.gameObject.SetActive(false); else _scrollHandleRT.gameObject.SetActive(true); 
+
+            _slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 0);
+            _slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight - _scrollBarRT.sizeDelta.x);
+        }
+
+        public void OnValueChanged(string currText)
+        {
+            Text = currText;
+            PruneItems(currText);
+            RedrawPanel();
+            //Debug.Log("value changed to: " + currText);
+
+            if (_panelItems.Count == 0)
+            {
+                _isPanelActive = true;//this makes it get turned off
+                ToggleDropdownPanel(false);
+            }
+            else if (!_isPanelActive)
+            {
+                ToggleDropdownPanel(false);
+            }
+
+			bool validity_changed = (_panelItems.Contains (Text) != _selectionIsValid);
+			_selectionIsValid = _panelItems.Contains (Text);
+			OnSelectionChanged.Invoke (Text, _selectionIsValid);
+			OnSelectionTextChanged.Invoke (Text);
+			if(validity_changed){
+				OnSelectionValidityChanged.Invoke (_selectionIsValid);
+			}
+
+			SetInputTextColor ();
+        }
+
+		private void SetInputTextColor(){
+			if (InputColorMatching) {
+				if (_selectionIsValid) {
+					_mainInput.textComponent.color = ValidSelectionTextColor;
+				} else if (_panelItems.Count > 0) {
+					_mainInput.textComponent.color = MatchingItemsRemainingTextColor;
+				} else {
+					_mainInput.textComponent.color = NoItemsRemainingTextColor;
+				}
+			}
+		}
+
+
+
+        /// <summary>
+        /// Toggle the drop down list
+        /// </summary>
+        /// <param name="directClick"> whether an item was directly clicked on</param>
+        public void ToggleDropdownPanel(bool directClick = false)
+        {
+            _isPanelActive = !_isPanelActive;
+
+            _overlayRT.gameObject.SetActive(_isPanelActive);
+            if (_isPanelActive)
+            {
+                transform.SetAsLastSibling();
+            }
+            else if (directClick)
+            {
+                // scrollOffset = Mathf.RoundToInt(itemsPanelRT.anchoredPosition.y / _rectTransform.sizeDelta.y); 
+            }
+        }
+
+        private void PruneItems(string currText)
+        {
+            if (autocompleteSearchType == AutoCompleteSearchType.Linq)
+            {
+                PruneItemsLinq(currText);
+            }
+            else
+            {
+                PruneItemsArray(currText);
+            }
+        }
+
+        private void PruneItemsLinq(string currText)
+        {
+            currText = currText.ToLower();
+            var toPrune = _panelItems.Where(x => !x.Contains(currText)).ToArray();
+            foreach (string key in toPrune)
+            {
+                panelObjects[key].SetActive(false);
+                _panelItems.Remove(key);
+                _prunedPanelItems.Add(key);
+            }
+
+            var toAddBack = _prunedPanelItems.Where(x => x.Contains(currText)).ToArray();
+            foreach (string key in toAddBack)
+            {
+                panelObjects[key].SetActive(true);
+                _panelItems.Add(key);
+                _prunedPanelItems.Remove(key);
+            }
+        }
+
+        //Updated to not use Linq
+        private void PruneItemsArray(string currText)
+        {
+            string _currText = currText.ToLower();
+
+            for (int i = _panelItems.Count - 1; i >= 0; i--)
+            {
+                string _item = _panelItems[i];
+                if (!_item.Contains(_currText))
+                {
+                    panelObjects[_panelItems[i]].SetActive(false);
+                    _panelItems.RemoveAt(i);
+                    _prunedPanelItems.Add(_item);
+                }
+            }
+            for (int i = _prunedPanelItems.Count - 1; i >= 0; i--)
+            {
+                string _item = _prunedPanelItems[i];
+                if (_item.Contains(_currText))
+                {
+                    panelObjects[_prunedPanelItems[i]].SetActive(true);
+                    _prunedPanelItems.RemoveAt(i);
+                    _panelItems.Add(_item);
+                }
+            }
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/AutoCompleteComboBox.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ef22b091ebae52c47aa3e86ad9040c05
+timeCreated: 1492278993
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 348 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/ComboBox.cs

@@ -0,0 +1,348 @@
+///Credit perchik
+///Sourced from - http://forum.unity3d.com/threads/receive-onclick-event-and-pass-it-on-to-lower-ui-elements.293642/
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace UnityEngine.UI.Extensions
+{
+    [RequireComponent(typeof(RectTransform))]
+    [AddComponentMenu("UI/Extensions/ComboBox")]
+    public class ComboBox : MonoBehaviour
+    {
+        public Color disabledTextColor;
+        public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it
+
+        public List<string> AvailableOptions;
+
+        [SerializeField]
+        private float _scrollBarWidth = 20.0f;
+
+        [SerializeField]
+        private int _itemsToDisplay;
+
+        //Sorting disabled as it causes issues.
+        //[SerializeField]
+        //private bool _sortItems = true;
+
+        [SerializeField]
+        private bool _displayPanelAbove = false;
+
+        [System.Serializable]
+        public class SelectionChangedEvent : UnityEngine.Events.UnityEvent<string>
+        {
+        }
+        // fires when item is changed;
+        public SelectionChangedEvent OnSelectionChanged;
+
+        //private bool isInitialized = false;
+        private bool _isPanelActive = false;
+        private bool _hasDrawnOnce = false;
+
+        private InputField _mainInput;
+        private RectTransform _inputRT;
+
+
+        private RectTransform _rectTransform;
+
+        private RectTransform _overlayRT;
+        private RectTransform _scrollPanelRT;
+        private RectTransform _scrollBarRT;
+        private RectTransform _slidingAreaRT;
+        private RectTransform _scrollHandleRT;
+        private RectTransform _itemsPanelRT;
+        private Canvas _canvas;
+        private RectTransform _canvasRT;
+
+        private ScrollRect _scrollRect;
+
+        private List<string> _panelItems; //items that will get shown in the drop-down
+
+        private Dictionary<string, GameObject> panelObjects;
+        
+        private GameObject itemTemplate;
+
+        public string Text { get; private set; }
+
+        public float ScrollBarWidth
+        {
+            get { return _scrollBarWidth; }
+            set
+            {
+                _scrollBarWidth = value;
+                RedrawPanel();
+            }
+        }
+
+        //    private int scrollOffset; //offset of the selected item
+        //    private int _selectedIndex = 0;
+
+        public int ItemsToDisplay
+        {
+            get { return _itemsToDisplay; }
+            set
+            {
+                _itemsToDisplay = value;
+                RedrawPanel();
+            }
+        }
+        
+        public void Awake()
+        {
+            Initialize();
+        }
+
+        public void Start()
+        {
+            RedrawPanel();
+        }
+
+        private bool Initialize()
+        {
+            bool success = true;
+            try
+            {
+                _rectTransform = GetComponent<RectTransform>();
+                _inputRT = _rectTransform.Find("InputField").GetComponent<RectTransform>();
+                _mainInput = _inputRT.GetComponent<InputField>();
+
+                _overlayRT = _rectTransform.Find("Overlay").GetComponent<RectTransform>();
+                _overlayRT.gameObject.SetActive(false);
+
+
+                _scrollPanelRT = _overlayRT.Find("ScrollPanel").GetComponent<RectTransform>();
+                _scrollBarRT = _scrollPanelRT.Find("Scrollbar").GetComponent<RectTransform>();
+                _slidingAreaRT = _scrollBarRT.Find("SlidingArea").GetComponent<RectTransform>();
+                _scrollHandleRT = _slidingAreaRT.Find("Handle").GetComponent<RectTransform>();
+                _itemsPanelRT = _scrollPanelRT.Find("Items").GetComponent<RectTransform>();
+                //itemPanelLayout = itemsPanelRT.gameObject.GetComponent<LayoutGroup>();
+
+                _canvas = GetComponentInParent<Canvas>();
+                _canvasRT = _canvas.GetComponent<RectTransform>();
+
+                _scrollRect = _scrollPanelRT.GetComponent<ScrollRect>();
+                _scrollRect.scrollSensitivity = _rectTransform.sizeDelta.y / 2;
+                _scrollRect.movementType = ScrollRect.MovementType.Clamped;
+                _scrollRect.content = _itemsPanelRT;
+
+                itemTemplate = _rectTransform.Find("ItemTemplate").gameObject;
+                itemTemplate.SetActive(false);
+            }
+            catch (System.NullReferenceException ex)
+            {
+                Debug.LogException(ex);
+                Debug.LogError("Something is setup incorrectly with the dropdownlist component causing a Null Reference Exception");
+                success = false;
+            }
+            panelObjects = new Dictionary<string, GameObject>();
+
+            _panelItems = AvailableOptions.ToList();
+
+            RebuildPanel();
+            //RedrawPanel();  - causes an initialisation failure in U5
+            return success;
+        }
+
+        public void AddItem(string item)
+        {
+            AvailableOptions.Add(item);
+            RebuildPanel();
+        }
+
+        public void RemoveItem(string item)
+        {
+            AvailableOptions.Remove(item);
+            RebuildPanel();
+        }
+
+        public void SetAvailableOptions(List<string> newOptions)
+        {
+            AvailableOptions.Clear();
+            AvailableOptions = newOptions;
+            RebuildPanel();
+        }
+
+        public void SetAvailableOptions(string[] newOptions)
+        {
+            AvailableOptions.Clear();
+
+            for (int i = 0; i < newOptions.Length; i++)
+            {
+                AvailableOptions.Add(newOptions[i]);
+            }
+            RebuildPanel();
+        }
+
+        public void ResetItems()
+        {
+            AvailableOptions.Clear();
+            RebuildPanel();
+        }
+
+        /// <summary>
+        /// Rebuilds the contents of the panel in response to items being added.
+        /// </summary>
+        private void RebuildPanel()
+        {
+            //panel starts with all options
+            _panelItems.Clear();
+            foreach (string option in AvailableOptions)
+            {
+                _panelItems.Add(option.ToLower());
+            }
+            //if(_sortItems) _panelItems.Sort();
+
+            List<GameObject> itemObjs = new List<GameObject>(panelObjects.Values);
+            panelObjects.Clear();
+
+            int indx = 0;
+            while (itemObjs.Count < AvailableOptions.Count)
+            {
+                GameObject newItem = Instantiate(itemTemplate) as GameObject;
+                newItem.name = "Item " + indx;
+                newItem.transform.SetParent(_itemsPanelRT, false);
+                itemObjs.Add(newItem);
+                indx++;
+            }
+
+            for (int i = 0; i < itemObjs.Count; i++)
+            {
+                itemObjs[i].SetActive(i <= AvailableOptions.Count);
+                if (i < AvailableOptions.Count)
+                {
+                    itemObjs[i].name = "Item " + i + " " + _panelItems[i];
+                    itemObjs[i].transform.Find("Text").GetComponent<Text>().text = AvailableOptions[i]; //set the text value
+
+                    Button itemBtn = itemObjs[i].GetComponent<Button>();
+                    itemBtn.onClick.RemoveAllListeners();
+                    string textOfItem = _panelItems[i]; //has to be copied for anonymous function or it gets garbage collected away
+                    itemBtn.onClick.AddListener(() =>
+                    {
+                        OnItemClicked(textOfItem);
+                    });
+                    panelObjects[_panelItems[i]] = itemObjs[i];
+                }
+            }
+        }
+
+        /// <summary>
+        /// what happens when an item in the list is selected
+        /// </summary>
+        /// <param name="item"></param>
+        private void OnItemClicked(string item)
+        {
+            //Debug.Log("item " + item + " clicked");
+            Text = item;
+            _mainInput.text = Text;
+            ToggleDropdownPanel(true);
+        }
+
+        //private void UpdateSelected()
+        //{
+        //    SelectedItem = (_selectedIndex > -1 && _selectedIndex < Items.Count) ? Items[_selectedIndex] : null;
+        //    if (SelectedItem == null) return;
+
+        //    bool hasImage = SelectedItem.Image != null;
+        //    if (hasImage)
+        //    {
+        //        mainButton.img.sprite = SelectedItem.Image;
+        //        mainButton.img.color = Color.white;
+
+        //        //if (Interactable) mainButton.img.color = Color.white;
+        //        //else mainButton.img.color = new Color(1, 1, 1, .5f);
+        //    }
+        //    else
+        //    {
+        //        mainButton.img.sprite = null;
+        //    }
+
+        //    mainButton.txt.text = SelectedItem.Caption;
+
+        //    //update selected index color
+        //    for (int i = 0; i < itemsPanelRT.childCount; i++)
+        //    {
+        //        panelItems[i].btnImg.color = (_selectedIndex == i) ? mainButton.btn.colors.highlightedColor : new Color(0, 0, 0, 0);
+        //    }
+        //}
+
+
+        private void RedrawPanel()
+        {
+            float scrollbarWidth = _panelItems.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items
+            _scrollBarRT.gameObject.SetActive(_panelItems.Count > ItemsToDisplay);
+            if (!_hasDrawnOnce || _rectTransform.sizeDelta != _inputRT.sizeDelta)
+            {
+                _hasDrawnOnce = true;
+                _inputRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
+                _inputRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _rectTransform.sizeDelta.y);
+
+                _scrollPanelRT.SetParent(transform, true);//break the scroll panel from the overlay
+                _scrollPanelRT.anchoredPosition = _displayPanelAbove ?
+                    new Vector2(0, _rectTransform.sizeDelta.y * ItemsToDisplay - 1)  : 
+                    new Vector2(0, -_rectTransform.sizeDelta.y); 
+
+                //make the overlay fill the screen
+                _overlayRT.SetParent(_canvas.transform, false); //attach it to top level object
+                _overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _canvasRT.sizeDelta.x);
+                _overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _canvasRT.sizeDelta.y);
+
+                _overlayRT.SetParent(transform, true);//reattach to this object
+                _scrollPanelRT.SetParent(_overlayRT, true); //reattach the scrollpanel to the overlay
+            }
+
+            if (_panelItems.Count < 1) return;
+
+            float dropdownHeight = _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, _panelItems.Count);
+
+            _scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
+            _scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
+
+            _itemsPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _scrollPanelRT.sizeDelta.x - scrollbarWidth - 5);
+            _itemsPanelRT.anchoredPosition = new Vector2(5, 0);
+
+            _scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, scrollbarWidth);
+            _scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
+            if (scrollbarWidth == 0) _scrollHandleRT.gameObject.SetActive(false); else _scrollHandleRT.gameObject.SetActive(true);
+
+            _slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 0);
+            _slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight - _scrollBarRT.sizeDelta.x);
+        }
+
+        public void OnValueChanged(string currText)
+        {
+            Text = currText;
+            RedrawPanel();
+            //Debug.Log("value changed to: " + currText);
+
+            if (_panelItems.Count == 0)
+            {
+                _isPanelActive = true;//this makes it get turned off
+                ToggleDropdownPanel(false);
+            }
+            else if (!_isPanelActive)
+            {
+                ToggleDropdownPanel(false);
+            }
+            OnSelectionChanged.Invoke(Text);
+        }
+
+        /// <summary>
+        /// Toggle the drop down list
+        /// </summary>
+        /// <param name="directClick"> whether an item was directly clicked on</param>
+        public void ToggleDropdownPanel(bool directClick)
+        {
+            _isPanelActive = !_isPanelActive;
+
+            _overlayRT.gameObject.SetActive(_isPanelActive);
+            if (_isPanelActive)
+            {
+                transform.SetAsLastSibling();
+            }
+            else if (directClick)
+            {
+                // scrollOffset = Mathf.RoundToInt(itemsPanelRT.anchoredPosition.y / _rectTransform.sizeDelta.y); 
+            }
+        }
+    }
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/ComboBox.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: cd26acd32e1be2747b9e5f3587b2b1d5
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 390 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownList.cs

@@ -0,0 +1,390 @@
+///Credit perchik
+///Sourced from - http://forum.unity3d.com/threads/receive-onclick-event-and-pass-it-on-to-lower-ui-elements.293642/
+
+
+using System.Collections.Generic;
+
+namespace UnityEngine.UI.Extensions
+{
+    /// <summary>
+    ///  Extension to the UI class which creates a dropdown list 
+    /// </summary>
+    [RequireComponent(typeof(RectTransform))]
+	[AddComponentMenu("UI/Extensions/Dropdown List")]
+	public class DropDownList : MonoBehaviour
+	{
+		public Color disabledTextColor;
+		public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it
+
+		[NonReorderable]
+		public List<DropDownListItem> Items;
+        public bool OverrideHighlighted = true;
+
+		//private bool isInitialized = false;
+		private bool _isPanelActive = false;
+		private bool _hasDrawnOnce = false;
+
+		private DropDownListButton _mainButton;
+
+		private RectTransform _rectTransform;
+
+		private RectTransform _overlayRT;
+		private RectTransform _scrollPanelRT;
+		private RectTransform _scrollBarRT;
+		private RectTransform _slidingAreaRT;
+		private RectTransform _scrollHandleRT;
+		private RectTransform _itemsPanelRT;
+		private Canvas _canvas;
+		private RectTransform _canvasRT;
+
+		private ScrollRect _scrollRect;
+
+		private List<DropDownListButton> _panelItems;
+
+		private GameObject _itemTemplate;
+
+		[SerializeField]
+		private float _scrollBarWidth = 20.0f;
+		public float ScrollBarWidth
+		{
+			get { return _scrollBarWidth; }
+			set
+			{
+				_scrollBarWidth = value;
+				RedrawPanel();
+			}
+		}
+
+		//    private int scrollOffset; //offset of the selected item
+		private int _selectedIndex = -1;
+
+		[SerializeField]
+		private int _itemsToDisplay;
+		public int ItemsToDisplay
+		{
+			get { return _itemsToDisplay; }
+			set
+			{
+				_itemsToDisplay = value;
+				RedrawPanel();
+			}
+		}
+
+		public bool SelectFirstItemOnStart = false;
+
+		[SerializeField]
+		private bool _displayPanelAbove = false;
+
+		[System.Serializable]
+		public class SelectionChangedEvent :  UnityEngine.Events.UnityEvent<int> {
+		}
+		// fires when item is changed;
+		public SelectionChangedEvent OnSelectionChanged;
+
+
+		public void Start()
+		{
+			Initialize();
+			if (SelectFirstItemOnStart && Items.Count > 0) {
+				ToggleDropdownPanel (false);
+				OnItemClicked (0);
+			}
+			RedrawPanel();
+		}
+
+		private bool Initialize()
+		{
+			bool success = true;
+			try
+			{
+				_rectTransform = GetComponent<RectTransform>();
+				_mainButton = new DropDownListButton(_rectTransform.Find("MainButton").gameObject);
+
+				_overlayRT = _rectTransform.Find("Overlay").GetComponent<RectTransform>();
+				_overlayRT.gameObject.SetActive(false);
+
+
+				_scrollPanelRT = _overlayRT.Find("ScrollPanel").GetComponent<RectTransform>();
+				_scrollBarRT = _scrollPanelRT.Find("Scrollbar").GetComponent<RectTransform>();
+				_slidingAreaRT = _scrollBarRT.Find("SlidingArea").GetComponent<RectTransform>();
+				_scrollHandleRT = _slidingAreaRT.Find("Handle").GetComponent<RectTransform>();
+				_itemsPanelRT = _scrollPanelRT.Find("Items").GetComponent<RectTransform>();
+				//itemPanelLayout = itemsPanelRT.gameObject.GetComponent<LayoutGroup>();
+
+				_canvas = GetComponentInParent<Canvas>();
+				_canvasRT = _canvas.GetComponent<RectTransform>();
+
+				_scrollRect = _scrollPanelRT.GetComponent<ScrollRect>();
+				_scrollRect.scrollSensitivity = _rectTransform.sizeDelta.y / 2;
+				_scrollRect.movementType = ScrollRect.MovementType.Clamped;
+				_scrollRect.content = _itemsPanelRT;
+
+
+				_itemTemplate = _rectTransform.Find("ItemTemplate").gameObject;
+				_itemTemplate.SetActive(false);
+			}
+			catch (System.NullReferenceException ex)
+			{
+				Debug.LogException(ex);
+				Debug.LogError("Something is setup incorrectly with the dropdownlist component causing a Null Reference Exception");
+				success = false;
+			}
+
+			_panelItems = new List<DropDownListButton>();
+
+			RebuildPanel();
+			RedrawPanel();
+			return success;
+		}
+
+		// currently just using items in the list instead of being able to add to it.
+		/// <summary>
+		/// Rebuilds the list from a new collection.
+		/// </summary>
+		/// <remarks>
+		/// NOTE, this will clear all existing items
+		/// </remarks>
+		/// <param name="list"></param>
+		public void RefreshItems(params object[] list)
+		{
+			Items.Clear();
+			List<DropDownListItem> ddItems = new List<DropDownListItem>();
+			foreach (var obj in list)
+			{
+				if (obj is DropDownListItem)
+				{
+					ddItems.Add((DropDownListItem)obj);
+				}
+				else if (obj is string)
+				{
+					ddItems.Add(new DropDownListItem(caption: (string)obj));
+				}
+				else if (obj is Sprite)
+				{
+					ddItems.Add(new DropDownListItem(image: (Sprite)obj));
+				}
+				else
+				{
+					throw new System.Exception("Only ComboBoxItems, Strings, and Sprite types are allowed");
+				}
+			}
+			Items.AddRange(ddItems);
+			RebuildPanel();
+		}
+
+		/// <summary>
+		/// Adds an additional item to the drop down list (recommended)
+		/// </summary>
+		/// <param name="item">Item of type DropDownListItem</param>
+		public void AddItem(DropDownListItem item)
+        {
+			Items.Add(item);
+			RebuildPanel();
+		}
+
+		/// <summary>
+		/// Adds an additional drop down list item using a string name 
+		/// </summary>
+		/// <param name="item">Item of type String</param>
+		public void AddItem(string item)
+		{
+			Items.Add(new DropDownListItem(caption: (string)item));
+			RebuildPanel();
+		}
+
+		/// <summary>
+		/// Adds an additional drop down list item using a sprite image 
+		/// </summary>
+		/// <param name="item">Item of type UI Sprite</param>
+		public void AddItem(Sprite item)
+		{
+			Items.Add(new DropDownListItem(image: (Sprite)item));
+			RebuildPanel();
+		}
+
+		/// <summary>
+		/// Removes an item from the drop down list (recommended)
+		/// </summary>
+		/// <param name="item">Item of type DropDownListItem</param>
+		public void RemoveItem(DropDownListItem item)
+		{
+			Items.Remove(item);
+			RebuildPanel();
+		}
+
+		/// <summary>
+		/// Removes an item from the drop down list item using a string name 
+		/// </summary>
+		/// <param name="item">Item of type String</param>
+		public void RemoveItem(string item)
+		{
+			Items.Remove(new DropDownListItem(caption: (string)item));
+			RebuildPanel();
+		}
+
+		/// <summary>
+		/// Removes an item from the drop down list item using a sprite image 
+		/// </summary>
+		/// <param name="item">Item of type UI Sprite</param>
+		public void RemoveItem(Sprite item)
+		{
+			Items.Remove(new DropDownListItem(image: (Sprite)item));
+			RebuildPanel();
+		}
+
+		public void ResetItems()
+		{
+			Items.Clear();
+			RebuildPanel();
+		}
+
+		/// <summary>
+		/// Rebuilds the contents of the panel in response to items being added.
+		/// </summary>
+		private void RebuildPanel()
+		{
+			if (Items.Count == 0) return;
+
+			int indx = _panelItems.Count;
+			while (_panelItems.Count < Items.Count)
+			{
+				GameObject newItem = Instantiate(_itemTemplate) as GameObject;
+				newItem.name = "Item " + indx;
+				newItem.transform.SetParent(_itemsPanelRT, false);
+
+				_panelItems.Add(new DropDownListButton(newItem));
+				indx++;
+			}
+			for (int i = 0; i < _panelItems.Count; i++)
+			{
+				if (i < Items.Count)
+				{
+					DropDownListItem item = Items[i];
+
+					_panelItems[i].txt.text = item.Caption;
+					if (item.IsDisabled) _panelItems[i].txt.color = disabledTextColor;
+
+					if (_panelItems[i].btnImg != null) _panelItems[i].btnImg.sprite = null;//hide the button image  
+					_panelItems[i].img.sprite = item.Image;
+					_panelItems[i].img.color = (item.Image == null) ? new Color(1, 1, 1, 0)
+																	: item.IsDisabled ? new Color(1, 1, 1, .5f)
+																					  : Color.white;
+					int ii = i; //have to copy the variable for use in anonymous function
+					_panelItems[i].btn.onClick.RemoveAllListeners();
+					_panelItems[i].btn.onClick.AddListener(() =>
+					{
+						OnItemClicked(ii);
+						if (item.OnSelect != null) item.OnSelect();
+					});
+				}
+				_panelItems[i].gameobject.SetActive(i < Items.Count);// if we have more thanks in the panel than Items in the list hide them
+			}
+		}
+
+		private void OnItemClicked(int indx)
+		{
+			//Debug.Log("item " + indx + " clicked");
+			if (indx != _selectedIndex && OnSelectionChanged != null) OnSelectionChanged.Invoke(indx);
+
+			_selectedIndex = indx;
+			ToggleDropdownPanel(true);
+			UpdateSelected();
+		}
+
+		private void UpdateSelected()
+		{
+			SelectedItem = (_selectedIndex > -1 && _selectedIndex < Items.Count) ? Items[_selectedIndex] : null;
+			if (SelectedItem == null) return;
+
+			bool hasImage = SelectedItem.Image != null;
+			if (hasImage)
+			{
+				_mainButton.img.sprite = SelectedItem.Image;
+				_mainButton.img.color = Color.white;
+
+				//if (Interactable) mainButton.img.color = Color.white;
+				//else mainButton.img.color = new Color(1, 1, 1, .5f);
+			}
+			else
+			{
+				_mainButton.img.sprite = null;
+			}
+
+			_mainButton.txt.text = SelectedItem.Caption;
+
+            //update selected index color
+            if (OverrideHighlighted)
+            {
+
+                for (int i = 0; i < _itemsPanelRT.childCount; i++)
+                {
+                    _panelItems[i].btnImg.color = (_selectedIndex == i) ? _mainButton.btn.colors.highlightedColor : new Color(0, 0, 0, 0);
+                }
+            }
+        }
+
+
+        private void RedrawPanel()
+		{
+			float scrollbarWidth = Items.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items
+
+			if (!_hasDrawnOnce || _rectTransform.sizeDelta != _mainButton.rectTransform.sizeDelta)
+			{
+				_hasDrawnOnce = true;
+				_mainButton.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
+				_mainButton.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _rectTransform.sizeDelta.y);
+				_mainButton.txt.rectTransform.offsetMax = new Vector2(4, 0);
+
+				_scrollPanelRT.SetParent(transform, true);//break the scroll panel from the overlay
+				_scrollPanelRT.anchoredPosition = _displayPanelAbove ?
+					new Vector2(0, _rectTransform.sizeDelta.y * ItemsToDisplay - 1) :
+					new Vector2(0, -_rectTransform.sizeDelta.y);
+
+				//make the overlay fill the screen
+				_overlayRT.SetParent(_canvas.transform, false); //attach it to top level object
+				_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _canvasRT.sizeDelta.x);
+				_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _canvasRT.sizeDelta.y);
+
+				_overlayRT.SetParent(transform, true);//reattach to this object
+				_scrollPanelRT.SetParent(_overlayRT, true); //reattach the scrollpanel to the overlay            
+			}
+
+			if (Items.Count < 1) return;
+
+			float dropdownHeight = _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, Items.Count);
+
+			_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
+			_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
+
+			_itemsPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _scrollPanelRT.sizeDelta.x - scrollbarWidth - 5);
+			_itemsPanelRT.anchoredPosition = new Vector2(5, 0);
+
+			_scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, scrollbarWidth);
+			_scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
+			if (scrollbarWidth == 0) _scrollHandleRT.gameObject.SetActive(false); else _scrollHandleRT.gameObject.SetActive(true);
+
+			_slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 0);
+			_slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight - _scrollBarRT.sizeDelta.x);
+		}
+
+		/// <summary>
+		/// Toggle the drop down list
+		/// </summary>
+		/// <param name="directClick"> whether an item was directly clicked on</param>
+		public void ToggleDropdownPanel(bool directClick)
+		{
+			_overlayRT.transform.localScale = new Vector3(1, 1, 1);
+			_scrollBarRT.transform.localScale = new Vector3(1, 1, 1);
+			_isPanelActive = !_isPanelActive;
+			_overlayRT.gameObject.SetActive(_isPanelActive);
+			if (_isPanelActive)
+			{
+				transform.SetAsLastSibling();
+			}
+			else if (directClick)
+			{
+				// scrollOffset = Mathf.RoundToInt(itemsPanelRT.anchoredPosition.y / _rectTransform.sizeDelta.y); 
+			}
+		}
+	}
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownList.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7a00cad80d8a47b438b394bebe77d0d2
+timeCreated: 1492278993
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 26 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownListButton.cs

@@ -0,0 +1,26 @@
+///Credit perchik
+///Sourced from - http://forum.unity3d.com/threads/receive-onclick-event-and-pass-it-on-to-lower-ui-elements.293642/
+
+namespace UnityEngine.UI.Extensions
+{
+    [RequireComponent(typeof(RectTransform), typeof(Button))]
+    public class DropDownListButton
+    {
+        public RectTransform rectTransform;
+        public Button btn;
+        public Text txt;
+        public Image btnImg;
+        public Image img;
+        public GameObject gameobject;
+
+        public DropDownListButton(GameObject btnObj)
+        {
+            gameobject = btnObj;
+            rectTransform = btnObj.GetComponent<RectTransform>();
+            btnImg = btnObj.GetComponent<Image>();
+            btn = btnObj.GetComponent<Button>();
+            txt = rectTransform.Find("Text").GetComponent<Text>();
+            img = rectTransform.Find("Image").GetComponent<Image>();
+        }
+    }
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownListButton.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 491c635e1f309294187ff24b5c71e8cb
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 100 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownListItem.cs

@@ -0,0 +1,100 @@
+///Credit perchik
+///Sourced from - http://forum.unity3d.com/threads/receive-onclick-event-and-pass-it-on-to-lower-ui-elements.293642/
+
+using System;
+
+namespace UnityEngine.UI.Extensions
+{
+    [Serializable]
+    public class DropDownListItem
+    {
+        [SerializeField]
+        private string _caption;
+        /// <summary>
+        /// Caption of the Item
+        /// </summary>
+        public string Caption
+        {
+            get
+            {
+                return _caption;
+            }
+            set
+            {
+                _caption = value;
+                if (OnUpdate != null)
+                    OnUpdate();
+            }
+        }
+
+        [SerializeField]
+        private Sprite _image;
+        /// <summary>
+        /// Image component of the Item
+        /// </summary>
+        public Sprite Image
+        {
+            get
+            {
+                return _image;
+            }
+            set
+            {
+                _image = value;
+                if (OnUpdate != null)
+                    OnUpdate();
+            }
+        }
+
+        [SerializeField]
+        private bool _isDisabled;
+        /// <summary>
+        /// Is the Item currently enabled?
+        /// </summary>
+        public bool IsDisabled
+        {
+            get
+            {
+                return _isDisabled;
+            }
+            set
+            {
+                _isDisabled = value;
+                if (OnUpdate != null)
+                    OnUpdate();
+            }
+        }
+
+        [SerializeField]
+        private string _id;
+        ///<summary>
+        ///ID exists so that an item can have a caption and a value like in traditional windows forms. IE. an item may be a student's name, and the ID can be the student's ID number
+        ///</summary>
+        public string ID
+        {
+            get { return _id; }
+            set { _id = value; }
+        }
+
+        public Action OnSelect = null; //action to be called when this item is selected
+
+        internal Action OnUpdate = null; //action to be called when something changes.  
+
+        /// <summary>
+        /// Constructor for Drop Down List panelItems
+        /// </summary>
+        /// <param name="caption">Caption for the item </param>
+        /// <param name="val">ID of the item </param>
+        /// <param name="image"></param>
+        /// <param name="disabled">Should the item start disabled</param>
+        /// <param name="onSelect">Action to be called when this item is selected</param>
+        public DropDownListItem(string caption = "", string inId = "", Sprite image = null, bool disabled = false, Action onSelect = null)
+        {
+            _caption = caption;
+            _image = image;
+            _id = inId;
+            _isDisabled = disabled;
+            OnSelect = onSelect;
+        }
+    }
+}

+ 8 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ComboBox/DropDownListItem.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e1dd512d0ed874740902b01df530b2dc
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 197 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/CooldownButton.cs

@@ -0,0 +1,197 @@
+/// Credit SimonDarksideJ
+/// Sourced from my head
+
+using UnityEngine.Events;
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    [AddComponentMenu("UI/Extensions/Cooldown Button")]
+    public class CooldownButton : MonoBehaviour, IPointerDownHandler
+    {
+        #region Sub-Classes
+        [System.Serializable]
+        public class CooldownButtonEvent : UnityEvent<PointerEventData.InputButton> { }
+        #endregion
+
+        #region Private variables
+
+        [SerializeField]
+        private float cooldownTimeout;
+        [SerializeField]
+        private float cooldownSpeed = 1;
+        [SerializeField][ReadOnly]
+        private bool cooldownActive;
+        [SerializeField][ReadOnly]
+        private bool cooldownInEffect;
+        [SerializeField][ReadOnly]
+        private float cooldownTimeElapsed;
+        [SerializeField][ReadOnly]
+        private float cooldownTimeRemaining;
+        [SerializeField][ReadOnly]
+        private int cooldownPercentRemaining;
+        [SerializeField][ReadOnly]
+        private int cooldownPercentComplete;
+
+        PointerEventData buttonSource;
+        #endregion
+
+        #region Public Properties
+
+        public float CooldownTimeout
+        {
+            get { return cooldownTimeout; }
+            set { cooldownTimeout = value; }
+        }
+
+        public float CooldownSpeed
+        {
+            get { return cooldownSpeed; }
+            set { cooldownSpeed = value; }
+        }
+
+        public bool CooldownInEffect
+        {
+            get { return cooldownInEffect; }
+        }
+
+        public bool CooldownActive
+        {
+            get { return cooldownActive; }
+            set { cooldownActive = value; }
+        }
+
+        public float CooldownTimeElapsed
+        {
+            get { return cooldownTimeElapsed; }
+            set { cooldownTimeElapsed = value; }
+        }
+
+        public float CooldownTimeRemaining
+        {
+            get { return cooldownTimeRemaining; }
+        }
+
+        public int CooldownPercentRemaining
+        {
+            get { return cooldownPercentRemaining; }
+        }
+
+        public int CooldownPercentComplete
+        {
+            get { return cooldownPercentComplete; }
+        }
+
+        #endregion
+
+        #region Events
+        [Tooltip("Event that fires when a button is initially pressed down")]
+        public CooldownButtonEvent OnCooldownStart;
+        [Tooltip("Event that fires when a button is released")]
+        public CooldownButtonEvent OnButtonClickDuringCooldown;
+        [Tooltip("Event that continually fires while a button is held down")]
+        public CooldownButtonEvent OnCoolDownFinish;
+        #endregion
+
+        #region Update
+
+        // Update is called once per frame
+        void Update()
+        {
+            if (CooldownActive)
+            {
+                cooldownTimeRemaining -= Time.deltaTime * cooldownSpeed;
+                cooldownTimeElapsed = CooldownTimeout - CooldownTimeRemaining;
+                if (cooldownTimeRemaining < 0)
+                {
+                    StopCooldown();
+                }
+                else
+                {
+                    cooldownPercentRemaining = (int)(100 * cooldownTimeRemaining * CooldownTimeout / 100);
+                    cooldownPercentComplete = (int)((CooldownTimeout - cooldownTimeRemaining) / CooldownTimeout * 100);
+                }
+            }
+        }
+        #endregion
+
+        #region Public Methods
+
+        /// <summary>
+        /// Pause Cooldown without resetting values, allows Restarting of cooldown
+        /// </summary>
+        public void PauseCooldown()
+        {
+            if (CooldownInEffect)
+            {
+                CooldownActive = false;
+            }
+        }
+
+        /// <summary>
+        /// Restart a paused cooldown
+        /// </summary>
+        public void RestartCooldown()
+        {
+            if (CooldownInEffect)
+            {
+                CooldownActive = true;
+            }
+        }
+
+        /// <summary>
+        /// Start a cooldown from outside
+        /// </summary>
+        public void StartCooldown()
+        {
+            PointerEventData emptySource = new PointerEventData(EventSystem.current);
+            buttonSource = emptySource;
+            OnCooldownStart.Invoke(emptySource.button);
+            cooldownTimeRemaining = cooldownTimeout;
+            CooldownActive = cooldownInEffect = true;
+        }
+
+        /// <summary>
+        /// Stop a running Cooldown and reset all values
+        /// </summary>
+        public void StopCooldown()
+        {
+            cooldownTimeElapsed = CooldownTimeout;
+            cooldownTimeRemaining = 0;
+            cooldownPercentRemaining = 0;
+            cooldownPercentComplete = 100;
+            cooldownActive = cooldownInEffect = false;
+            if (OnCoolDownFinish != null) OnCoolDownFinish.Invoke(buttonSource.button);
+        }
+
+        /// <summary>
+        /// Stop a running Cooldown and retain current values
+        /// </summary>
+        public void CancelCooldown()
+        {
+            cooldownActive = cooldownInEffect = false;
+        }
+
+        #endregion
+
+        #region IPointerDownHandler
+
+        void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
+        {
+            buttonSource = eventData;
+            if (CooldownInEffect)
+            {
+                if (OnButtonClickDuringCooldown != null) OnButtonClickDuringCooldown.Invoke(eventData.button);
+            }
+            if (!CooldownInEffect)
+            {
+                if(OnCooldownStart != null) OnCooldownStart.Invoke(eventData.button);
+                cooldownTimeRemaining = cooldownTimeout;
+                cooldownActive = cooldownInEffect = true;
+            }
+        }
+
+        #endregion
+
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/CooldownButton.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 74a62d95b3be0fe47871dd48fca58b7d
+timeCreated: 1498387990
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 83 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/InputFocus.cs

@@ -0,0 +1,83 @@
+/// Credit Zelek
+/// Sourced from - http://forum.unity3d.com/threads/inputfield-focus-and-unfocus.306634/
+/// Usage, assign component to Input field, set OnEndEdit function to the one in this script and the Click for the submit button to the buttonPressed function.
+
+namespace UnityEngine.UI.Extensions
+{
+    [RequireComponent(typeof(InputField))]
+	[AddComponentMenu("UI/Extensions/InputFocus")]
+    public class InputFocus : MonoBehaviour
+    {
+        #region Private Variables
+
+        // The input field we use for chat
+        protected InputField _inputField;
+
+        // When set to true, we will ignore the next time the "Enter" key is released
+        public bool _ignoreNextActivation = false;
+
+        #endregion
+
+        void Start()
+        {
+            _inputField = GetComponent<InputField>();
+        }
+
+        void Update()
+        {
+            // Check if the "Enter" key was just released with the chat input not focused
+            if (UIExtensionsInputManager.GetKeyUp(KeyCode.Return) && !_inputField.isFocused)
+            {
+                // If we need to ignore the keypress, do nothing - otherwise activate the input field
+                if (_ignoreNextActivation)
+                {
+                    _ignoreNextActivation = false;
+                }
+                else
+                {
+                    _inputField.Select();
+                    _inputField.ActivateInputField();
+                }
+            }
+        }
+
+        public void buttonPressed()
+        {
+            // Do whatever you want with the input field text here
+
+            // Make note of whether the input string was empty, and then clear it out
+            bool wasEmpty = _inputField.text == "";
+            _inputField.text = "";
+
+            // If the string was not empty, we should reactivate the input field
+            if (!wasEmpty)
+            {
+                _inputField.Select();
+                _inputField.ActivateInputField();
+            }
+        }
+
+        public void OnEndEdit(string textString)
+        {
+            // If the edit ended because we clicked away, don't do anything extra
+            if (!UIExtensionsInputManager.GetKeyDown(KeyCode.Return))
+            {
+                return;
+            }
+
+            // Do whatever you want with the input field text here
+
+            // Make note of whether the input string was empty, and then clear it out
+            bool wasEmpty = _inputField.text == "";
+            _inputField.text = "";
+
+            // if the input string was empty, then allow the field to deactivate
+            if (wasEmpty)
+            {
+                _ignoreNextActivation = true;
+            }
+        }
+
+
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/InputFocus.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: a18c7c81729dadf40aee407a0cff0462
+timeCreated: 1440843410
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 39 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/MultiTouchScrollRect.cs

@@ -0,0 +1,39 @@
+/// Credit Erdener Gonenc - @PixelEnvision
+/*USAGE: Simply use that instead of the regular ScrollRect */
+
+
+namespace UnityEngine.UI.Extensions
+{
+    [AddComponentMenu ("UI/Extensions/MultiTouchScrollRect")]
+	public class MultiTouchScrollRect : ScrollRect
+	{
+		private int pid = -100;
+
+		/// <summary>
+		/// Begin drag event
+		/// </summary>
+		public override void OnBeginDrag (UnityEngine.EventSystems.PointerEventData eventData)
+		{
+			pid = eventData.pointerId;
+			base.OnBeginDrag (eventData);
+		}
+
+		/// <summary>
+		/// Drag event
+		/// </summary>
+		public override void OnDrag (UnityEngine.EventSystems.PointerEventData eventData)
+		{
+			if (pid == eventData.pointerId)
+				base.OnDrag (eventData);
+		}
+
+		/// <summary>
+		/// End drag event
+		/// </summary>
+		public override void OnEndDrag (UnityEngine.EventSystems.PointerEventData eventData)
+		{
+				pid = -100;
+				base.OnEndDrag (eventData);
+		}
+	}
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/MultiTouchScrollRect.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 9f2bebd34aaa76541b97e61752a7d262
+timeCreated: 1492273203
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 258 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RadialSlider.cs

@@ -0,0 +1,258 @@
+/// Credit mgear, SimonDarksideJ
+/// Sourced from - https://forum.unity3d.com/threads/radial-slider-circle-slider.326392/#post-3143582
+/// Updated to include lerping features and programmatic access to angle/value
+
+using System;
+using UnityEngine.Events;
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    [AddComponentMenu("UI/Extensions/Radial Slider")]
+    [RequireComponent(typeof(Image))]
+    public class RadialSlider : MonoBehaviour, IPointerEnterHandler, IPointerDownHandler, IPointerUpHandler, IDragHandler
+    {
+        private bool isPointerDown, isPointerReleased, lerpInProgress;
+        private Vector2 m_localPos, m_screenPos; 
+        private float m_targetAngle, m_lerpTargetAngle, m_startAngle, m_currentLerpTime, m_lerpTime;
+        private Camera m_eventCamera;
+        private Image m_image;
+
+        [SerializeField]
+        [Tooltip("Radial Gradient Start Color")]
+        private Color m_startColor = Color.green;
+        [SerializeField]
+        [Tooltip("Radial Gradient End Color")]
+        private Color m_endColor = Color.red;
+        [Tooltip("Move slider absolute or use Lerping?\nDragging only supported with absolute")]
+        [SerializeField]
+        private bool m_lerpToTarget;
+        [Tooltip("Curve to apply to the Lerp\nMust be set to enable Lerp")]
+        [SerializeField]
+        private AnimationCurve m_lerpCurve;
+        [Tooltip("Event fired when value of control changes, outputs an INT angle value")]
+        [SerializeField]
+        private RadialSliderValueChangedEvent _onValueChanged = new RadialSliderValueChangedEvent();
+        [Tooltip("Event fired when value of control changes, outputs a TEXT angle value")]
+        [SerializeField]
+        private RadialSliderTextValueChangedEvent _onTextValueChanged = new RadialSliderTextValueChangedEvent();
+
+        public float Angle
+        {
+            get { return RadialImage.fillAmount * 360f; }
+            set
+            {
+                if (LerpToTarget)
+                {
+                    StartLerp(value / 360f);
+                }
+                else
+                {
+                    UpdateRadialImage(value / 360f);
+                }
+            }
+        }
+
+        public float Value
+        {
+            get { return RadialImage.fillAmount; }
+            set
+            {
+                if (LerpToTarget)
+                {
+                    StartLerp(value);
+                }
+                else
+                {
+                    UpdateRadialImage(value);
+                }
+            }
+        }
+
+        public Color EndColor
+        {
+            get { return m_endColor; }
+            set { m_endColor = value; }
+        }
+
+        public Color StartColor
+        {
+            get { return m_startColor; }
+            set { m_startColor = value; }
+        }
+
+        public bool LerpToTarget
+        {
+            get { return m_lerpToTarget; }
+            set { m_lerpToTarget = value; }
+        }
+
+        public AnimationCurve LerpCurve
+        {
+            get { return m_lerpCurve; }
+            set { m_lerpCurve = value; m_lerpTime = LerpCurve[LerpCurve.length - 1].time; }
+        }
+
+        public bool LerpInProgress
+        {
+            get { return lerpInProgress; }
+        }
+
+        [Serializable]
+        public class RadialSliderValueChangedEvent : UnityEvent<int> { }
+        [Serializable]
+        public class RadialSliderTextValueChangedEvent : UnityEvent<string> { }
+
+        public Image RadialImage
+        {
+            get
+            {
+                if (m_image == null)
+                {
+                    m_image = GetComponent<Image>();
+                    m_image.type = Image.Type.Filled;
+                    m_image.fillMethod = Image.FillMethod.Radial360;
+                    m_image.fillAmount = 0;
+                }
+                return m_image;
+            }
+        }
+
+        public RadialSliderValueChangedEvent onValueChanged
+        {
+            get { return _onValueChanged; }
+            set { _onValueChanged = value; }
+        }
+        public RadialSliderTextValueChangedEvent onTextValueChanged
+        {
+            get { return _onTextValueChanged; }
+            set { _onTextValueChanged = value; }
+        }
+
+        private void Awake()
+        {
+            if (LerpCurve != null && LerpCurve.length > 0)
+            {
+                m_lerpTime = LerpCurve[LerpCurve.length - 1].time;
+            }
+            else
+            {
+                m_lerpTime = 1;
+            }
+        }
+
+        private void Update()
+        {
+            if (isPointerDown)
+            {
+                m_targetAngle = GetAngleFromMousePoint();
+                if (!lerpInProgress)
+                {
+                    if (!LerpToTarget)
+                    {
+                        UpdateRadialImage(m_targetAngle);
+
+                        NotifyValueChanged();
+                    }
+                    else
+                    {
+                        if (isPointerReleased) StartLerp(m_targetAngle);
+                        isPointerReleased = false;
+                    }
+                }
+            }
+            if (lerpInProgress && Value != m_lerpTargetAngle)
+            {
+                m_currentLerpTime += Time.deltaTime;
+                float perc = m_currentLerpTime / m_lerpTime;
+                if (LerpCurve != null && LerpCurve.length > 0)
+                {
+                    UpdateRadialImage(Mathf.Lerp(m_startAngle, m_lerpTargetAngle, LerpCurve.Evaluate(perc)));
+                }
+                else
+                {
+                    UpdateRadialImage(Mathf.Lerp(m_startAngle, m_lerpTargetAngle, perc));
+                }
+            }
+            if (m_currentLerpTime >= m_lerpTime || Value == m_lerpTargetAngle)
+            {
+                lerpInProgress = false;
+                UpdateRadialImage(m_lerpTargetAngle);
+                NotifyValueChanged();
+            }
+        }
+
+        private void StartLerp(float targetAngle)
+        {
+            if (!lerpInProgress)
+            {
+                m_startAngle = Value;
+                m_lerpTargetAngle = targetAngle;
+                m_currentLerpTime = 0f;
+                lerpInProgress = true;
+            }
+        }
+
+        private float GetAngleFromMousePoint()
+        {
+            RectTransformUtility.ScreenPointToLocalPointInRectangle(transform as RectTransform, m_screenPos, m_eventCamera, out m_localPos);
+
+            // radial pos of the mouse position.
+            return (Mathf.Atan2(-m_localPos.y, m_localPos.x) * 180f / Mathf.PI + 180f) / 360f;
+        }
+
+        private void UpdateRadialImage(float targetAngle)
+        {
+            RadialImage.fillAmount = targetAngle;
+
+            RadialImage.color = Color.Lerp(m_startColor, m_endColor, targetAngle);
+        }
+
+        private void NotifyValueChanged()
+        {
+            _onValueChanged.Invoke((int)(m_targetAngle * 360f));
+            _onTextValueChanged.Invoke(((int)(m_targetAngle * 360f)).ToString());
+        }
+
+//#if UNITY_EDITOR
+
+//        private void OnValidate()
+//        {
+//            if (LerpToTarget && LerpCurve.length < 2)
+//            {
+//                LerpToTarget = false;
+//                Debug.LogError("You need to define a Lerp Curve to enable 'Lerp To Target'");
+//            }
+//        }
+//#endif
+
+        #region Interfaces
+        // Called when the pointer enters our GUI component.
+        // Start tracking the mouse
+        public void OnPointerEnter(PointerEventData eventData)
+        {
+            m_screenPos = eventData.position;
+            m_eventCamera = eventData.enterEventCamera;
+        }
+
+        public void OnPointerDown(PointerEventData eventData)
+        {
+            m_screenPos = eventData.position;
+            m_eventCamera = eventData.enterEventCamera;
+            isPointerDown = true;
+        }
+
+        public void OnPointerUp(PointerEventData eventData)
+        {
+            m_screenPos = Vector2.zero;
+            isPointerDown = false;
+            isPointerReleased = true;
+        }
+
+        public void OnDrag(PointerEventData eventData)
+        {
+            m_screenPos = eventData.position;
+        }
+        #endregion
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RadialSlider.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 803cebee00d5c504e930205383017dc1
+timeCreated: 1432062988
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 604 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RangeSlider.cs

@@ -0,0 +1,604 @@
+/// Credit Ben MacKinnon @Dover8
+/// Sourced from - https://github.com/Dover8/Unity-UI-Extensions/tree/range-slider
+/// Usage: Extension of the standard slider. Two handles determine a low and high value between a Min and Max. 
+/// Raises a UnityEvent passing the low and high values
+
+using System;
+using UnityEngine.Events;
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    [AddComponentMenu("UI/Extensions/Range Slider", 34)]
+    [ExecuteInEditMode]
+    [RequireComponent(typeof(RectTransform))]
+    public class RangeSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
+    {
+
+        [Serializable]
+        public class RangeSliderEvent : UnityEvent<float, float> { }
+
+        [SerializeField]
+        private RectTransform m_FillRect;
+
+        public RectTransform FillRect { get { return m_FillRect; } set { if (SetClass(ref m_FillRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
+
+        [SerializeField]
+        private RectTransform m_LowHandleRect;
+
+        public RectTransform LowHandleRect { get { return m_LowHandleRect; } set { if (SetClass(ref m_LowHandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
+
+        [SerializeField]
+        private RectTransform m_HighHandleRect;
+
+        public RectTransform HighHandleRect { get { return m_HighHandleRect; } set { if (SetClass(ref m_HighHandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
+
+        [Space]
+
+        [SerializeField]
+        private float m_MinValue = 0;
+
+        public float MinValue { get { return m_MinValue; } set { if (SetStruct(ref m_MinValue, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
+
+
+        [SerializeField]
+        private float m_MaxValue = 1;
+
+        public float MaxValue { get { return m_MaxValue; } set { if (SetStruct(ref m_MaxValue, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
+
+        [SerializeField]
+        private bool m_WholeNumbers = false;
+
+        public bool WholeNumbers { get { return m_WholeNumbers; } set { if (SetStruct(ref m_WholeNumbers, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
+
+        [SerializeField]
+        private float m_LowValue;
+        public virtual float LowValue
+        {
+            get
+            {
+                if (WholeNumbers)
+                {
+                    return Mathf.Round(m_LowValue);
+                }
+
+                return m_LowValue;
+            }
+            set
+            {
+                SetLow(value);
+            }
+        }
+
+        public float NormalizedLowValue
+        {
+            get
+            {
+                if (Mathf.Approximately(MinValue, MaxValue))
+                {
+                    return 0;
+                }
+                return Mathf.InverseLerp(MinValue, MaxValue, LowValue);
+            }
+            set
+            {
+                this.LowValue = Mathf.Lerp(MinValue, MaxValue, value);
+            }
+        }
+
+
+        [SerializeField]
+        private float m_HighValue;
+        public virtual float HighValue
+        {
+            get
+            {
+                if (WholeNumbers)
+                {
+                    return Mathf.Round(m_HighValue);
+                }
+
+                return m_HighValue;
+            }
+            set
+            {
+                SetHigh(value);
+            }
+        }
+
+        public float NormalizedHighValue
+        {
+            get
+            {
+                if (Mathf.Approximately(MinValue, MaxValue))
+                {
+                    return 0;
+                }
+                return Mathf.InverseLerp(MinValue, MaxValue, HighValue);
+            }
+            set
+            {
+                this.HighValue = Mathf.Lerp(MinValue, MaxValue, value);
+            }
+        }
+
+        /// <summary>
+        /// Set the value of the slider without invoking onValueChanged callback.
+        /// </summary>
+        /// <param name="input">The new value for the slider.</param>
+        public virtual void SetValueWithoutNotify(float low, float high)
+        {
+            SetLow(low, false);
+            SetHigh(high, false);
+        }
+
+        [Space]
+
+        [SerializeField]
+        private RangeSliderEvent m_OnValueChanged = new RangeSliderEvent();
+
+        public RangeSliderEvent OnValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
+
+        // Private fields
+
+        /// <summary>
+        /// An Enum that says in what state we and interacting with the slider
+        /// </summary>
+        private enum InteractionState
+        {
+            Low,
+            High,
+            Bar,
+            None
+        }
+
+        private InteractionState interactionState = InteractionState.None;
+
+        private Image m_FillImage;
+        private Transform m_FillTransform;
+        private RectTransform m_FillContainerRect;
+        private Transform m_HighHandleTransform;
+        private RectTransform m_HighHandleContainerRect;
+        private Transform m_LowHandleTransform;
+        private RectTransform m_LowHandleContainerRect;
+
+        // The offset from handle position to mouse down position
+        private Vector2 m_LowOffset = Vector2.zero;
+        // The offset from handle position to mouse down position
+        private Vector2 m_HighOffset = Vector2.zero;
+
+        private DrivenRectTransformTracker m_Tracker;
+
+        // This "delayed" mechanism is required for case 1037681.
+        private bool m_DelayedUpdateVisuals = false;
+
+        // Size of each step.
+        float StepSize { get { return WholeNumbers ? 1 : (MaxValue - MinValue) * 0.1f; } }
+
+        protected RangeSlider()
+        { }
+
+#if UNITY_EDITOR
+        protected override void OnValidate()
+        {
+            base.OnValidate();
+
+            if (WholeNumbers)
+            {
+                m_MinValue = Mathf.Round(m_MinValue);
+                m_MaxValue = Mathf.Round(m_MaxValue);
+            }
+
+            if (IsActive())
+            {
+                UpdateCachedReferences();
+                SetLow(m_LowValue, false);
+                SetHigh(m_HighValue, false);
+                //Update rects since other things might affect them even if value didn't change
+                m_DelayedUpdateVisuals = true;
+            }
+
+            if (!UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) && !Application.isPlaying)
+            {
+                CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
+            }
+        }
+#endif
+
+        public virtual void Rebuild(CanvasUpdate executing)
+        {
+#if UNITY_EDITOR
+            if (executing == CanvasUpdate.Prelayout)
+            {
+                OnValueChanged.Invoke(LowValue, HighValue);
+            }
+#endif
+        }
+
+        /// <summary>
+        /// See ICanvasElement.LayoutComplete
+        /// </summary>
+        public virtual void LayoutComplete()
+        { }
+
+        /// <summary>
+        /// See ICanvasElement.GraphicUpdateComplete
+        /// </summary>
+        public virtual void GraphicUpdateComplete()
+        { }
+
+        public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
+        {
+            if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
+                return false;
+
+            currentValue = newValue;
+            return true;
+        }
+
+        public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
+        {
+            if (currentValue.Equals(newValue))
+                return false;
+
+            currentValue = newValue;
+            return true;
+        }
+
+        protected override void OnEnable()
+        {
+            base.OnEnable();
+            UpdateCachedReferences();
+            SetLow(LowValue, false);
+            SetHigh(HighValue, false);
+            // Update rects since they need to be initialized correctly.
+            UpdateVisuals();
+        }
+
+        protected override void OnDisable()
+        {
+            m_Tracker.Clear();
+            base.OnDisable();
+        }
+
+        /// <summary>
+        /// Update the rect based on the delayed update visuals.
+        /// Got around issue of calling sendMessage from onValidate.
+        /// </summary>
+        protected virtual void Update()
+        {
+            if (m_DelayedUpdateVisuals)
+            {
+                m_DelayedUpdateVisuals = false;
+                UpdateVisuals();
+            }
+        }
+
+        protected override void OnDidApplyAnimationProperties()
+        {
+            base.OnDidApplyAnimationProperties();
+        }
+
+        void UpdateCachedReferences()
+        {
+            if (m_FillRect && m_FillRect != (RectTransform)transform)
+            {
+                m_FillTransform = m_FillRect.transform;
+                m_FillImage = m_FillRect.GetComponent<Image>();
+                if (m_FillTransform.parent != null)
+                    m_FillContainerRect = m_FillTransform.parent.GetComponent<RectTransform>();
+            }
+            else
+            {
+                m_FillRect = null;
+                m_FillContainerRect = null;
+                m_FillImage = null;
+            }
+
+            if (m_HighHandleRect && m_HighHandleRect != (RectTransform)transform)
+            {
+                m_HighHandleTransform = m_HighHandleRect.transform;
+                if (m_HighHandleTransform.parent != null)
+                    m_HighHandleContainerRect = m_HighHandleTransform.parent.GetComponent<RectTransform>();
+            }
+            else
+            {
+                m_HighHandleRect = null;
+                m_HighHandleContainerRect = null;
+            }
+
+            if (m_LowHandleRect && m_LowHandleRect != (RectTransform)transform)
+            {
+                m_LowHandleTransform = m_LowHandleRect.transform;
+                if (m_LowHandleTransform.parent != null)
+                {
+                    m_LowHandleContainerRect = m_LowHandleTransform.parent.GetComponent<RectTransform>();
+                }
+            }
+            else
+            {
+                m_LowHandleRect = null;
+                m_LowHandleContainerRect = null;
+            }
+        }
+        
+        void SetLow(float input)
+        {
+            SetLow(input, true);
+        }
+
+        protected virtual void SetLow(float input, bool sendCallback)
+        {
+            // Clamp the input
+            float newValue = Mathf.Clamp(input, MinValue, HighValue); //clamp between min and High
+            if (WholeNumbers)
+            {
+                newValue = Mathf.Round(newValue);
+            }
+
+            // If the stepped value doesn't match the last one, it's time to update
+            if (m_LowValue == newValue)
+                return;
+
+            m_LowValue = newValue;
+            UpdateVisuals();
+            if (sendCallback)
+            {
+                UISystemProfilerApi.AddMarker("RangeSlider.lowValue", this);
+                m_OnValueChanged.Invoke(newValue, HighValue);
+            }
+        }
+
+        void SetHigh(float input)
+        {
+            SetHigh(input, true);
+        }
+
+        protected virtual void SetHigh(float input, bool sendCallback)
+        {
+            // Clamp the input
+            float newValue = Mathf.Clamp(input, LowValue, MaxValue); //clamp between min and High
+            if (WholeNumbers)
+            {
+                newValue = Mathf.Round(newValue);
+            }
+
+            // If the stepped value doesn't match the last one, it's time to update
+            if (m_HighValue == newValue)
+                return;
+
+            m_HighValue = newValue;
+            UpdateVisuals();
+            if (sendCallback)
+            {
+                UISystemProfilerApi.AddMarker("RangeSlider.highValue", this);
+                m_OnValueChanged.Invoke(LowValue, newValue);
+            }
+        }
+
+
+        protected override void OnRectTransformDimensionsChange()
+        {
+            base.OnRectTransformDimensionsChange();
+
+            //This can be invoked before OnEnabled is called. So we shouldn't be accessing other objects, before OnEnable is called.
+            if (!IsActive())
+                return;
+
+            UpdateVisuals();
+        }
+
+
+        // Force-update the slider. Useful if you've changed the properties and want it to update visually.
+        private void UpdateVisuals()
+        {
+#if UNITY_EDITOR
+            if (!Application.isPlaying)
+                UpdateCachedReferences();
+#endif
+
+            m_Tracker.Clear();
+
+            if (m_FillContainerRect != null)
+            {
+                m_Tracker.Add(this, m_FillRect, DrivenTransformProperties.Anchors);
+                Vector2 anchorMin = Vector2.zero;
+                Vector2 anchorMax = Vector2.one;
+
+                //this is where some new magic must happen. Slider just uses a filled image
+                //and changes the % of fill. We must move the image anchors to be between the two handles.
+                anchorMin[0] = NormalizedLowValue;
+                anchorMax[0] = NormalizedHighValue;
+
+                m_FillRect.anchorMin = anchorMin;
+                m_FillRect.anchorMax = anchorMax;
+            }
+
+            if (m_LowHandleContainerRect != null)
+            {
+                m_Tracker.Add(this, m_LowHandleRect, DrivenTransformProperties.Anchors);
+                Vector2 anchorMin = Vector2.zero;
+                Vector2 anchorMax = Vector2.one;
+                anchorMin[0] = anchorMax[0] = NormalizedLowValue;
+                m_LowHandleRect.anchorMin = anchorMin;
+                m_LowHandleRect.anchorMax = anchorMax;
+            }
+
+            if (m_HighHandleContainerRect != null)
+            {
+                m_Tracker.Add(this, m_HighHandleRect, DrivenTransformProperties.Anchors);
+                Vector2 anchorMin = Vector2.zero;
+                Vector2 anchorMax = Vector2.one;
+                anchorMin[0] = anchorMax[0] = NormalizedHighValue;
+                m_HighHandleRect.anchorMin = anchorMin;
+                m_HighHandleRect.anchorMax = anchorMax;
+            }
+        }
+
+        // Update the slider's position based on the mouse.
+        void UpdateDrag(PointerEventData eventData, Camera cam)
+        {
+            //this needs to differ from slider in that we have two handles, and need to move the right one. 
+            //and if it was neither handle, we will have a separate case where both handles move uniformly 
+            //moving the entire range
+
+            //this is where we use our interationState
+            switch (interactionState)
+            {
+                case InteractionState.Low:
+                    NormalizedLowValue = CalculateDrag(eventData, cam, m_LowHandleContainerRect, m_LowOffset);
+                    break;
+                case InteractionState.High:
+                    NormalizedHighValue = CalculateDrag(eventData, cam, m_HighHandleContainerRect, m_HighOffset);
+                    break;
+                case InteractionState.Bar:
+                    //special case
+                    CalculateBarDrag(eventData, cam);
+                    break;
+                case InteractionState.None:
+                    break;
+            }
+        }
+
+        private float CalculateDrag(PointerEventData eventData, Camera cam, RectTransform containerRect, Vector2 offset)
+        { 
+            RectTransform clickRect = containerRect ?? m_FillContainerRect;
+            if (clickRect != null && clickRect.rect.size[0] > 0)
+            {
+                Vector2 localCursor;
+                if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
+                {
+                    return 0f;
+                }
+                localCursor -= clickRect.rect.position;
+
+                float val = Mathf.Clamp01((localCursor - offset)[0] / clickRect.rect.size[0]);
+
+                return val;
+            }
+            return 0;
+        }
+
+        private void CalculateBarDrag(PointerEventData eventData, Camera cam)
+        {
+            RectTransform clickRect = m_FillContainerRect;
+            if (clickRect != null && clickRect.rect.size[0] > 0)
+            {
+                Vector2 localCursor;
+                if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
+                {
+                    return;
+                }
+                localCursor -= clickRect.rect.position;
+
+                //now we need to get the delta drag on the bar
+                //and move both the normalized low and high values by this amount
+                //but also check that neither is going beyond the bounds
+                if (NormalizedLowValue >= 0 && NormalizedHighValue <= 1)
+                {
+                    //find the mid point on the current bar
+                    float mid = (NormalizedHighValue + NormalizedLowValue)/2;
+                    //find where the new mid point should be
+                    float val = Mathf.Clamp01((localCursor)[0] / clickRect.rect.size[0]);
+                    //calculate the delta
+                    float delta = val - mid;
+                    //check the clamp range
+                    if (NormalizedLowValue + delta < 0)
+                    {
+                        delta = -NormalizedLowValue;
+                    }
+                    else if (NormalizedHighValue + delta > 1)
+                    {
+                        delta = 1 - NormalizedHighValue;
+                    }
+
+                    //adjust both ends
+                    NormalizedLowValue += delta;
+                    NormalizedHighValue += delta;
+                }
+            }
+        }
+
+        private bool MayDrag(PointerEventData eventData)
+        {
+            return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
+        }
+
+        public override void OnPointerDown(PointerEventData eventData)
+        {
+            if (!MayDrag(eventData))
+                return;
+
+
+            //HANDLE DRAG EVENTS
+            m_LowOffset = m_HighOffset = Vector2.zero;
+            Vector2 localMousePos;
+            if (m_HighHandleRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HighHandleRect, eventData.position, eventData.enterEventCamera))
+            {
+                //dragging the high value handle
+                if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HighHandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
+                {
+                    m_HighOffset = localMousePos;
+                }
+                interactionState = InteractionState.High;
+                if (transition == Transition.ColorTint)
+                {
+                    targetGraphic = m_HighHandleRect.GetComponent<Graphic>();
+                }
+            }
+            else if (m_LowHandleRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_LowHandleRect, eventData.position, eventData.enterEventCamera))
+            {
+                //dragging the low value handle
+                if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_LowHandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
+                {
+                    m_LowOffset = localMousePos;
+                }
+                interactionState = InteractionState.Low;
+                if (transition == Transition.ColorTint)
+                {
+                    targetGraphic = m_LowHandleRect.GetComponent<Graphic>();
+                }
+            }
+            else
+            {
+                //outside the handles, move the entire slider along
+                UpdateDrag(eventData, eventData.pressEventCamera);
+                if (eventData.pointerCurrentRaycast.gameObject == m_FillRect.gameObject)
+                {
+                    interactionState = InteractionState.Bar;
+                }
+                if (transition == Transition.ColorTint)
+                {
+                    targetGraphic = m_FillImage;
+                }
+            }
+            base.OnPointerDown(eventData);
+        }
+
+        public virtual void OnDrag(PointerEventData eventData)
+        {
+            if (!MayDrag(eventData))
+            {
+                return;
+            }
+
+            UpdateDrag(eventData, eventData.pressEventCamera);
+        }
+
+        public override void OnPointerUp(PointerEventData eventData)
+        {
+            base.OnPointerUp(eventData);
+            interactionState = InteractionState.None;
+        }
+
+        public override void OnMove(AxisEventData eventData)
+        {
+            //this requires further investigation
+        }
+
+        public virtual void OnInitializePotentialDrag(PointerEventData eventData)
+        {
+            eventData.useDragThreshold = false;
+        }
+    }
+}

+ 11 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RangeSlider.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4735d2b59d5c699488c30a34a6a76e72
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 281614f4c0e3b7a4d9056bd377134172
+folderAsset: yes
+timeCreated: 1446117980
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 156 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableList.cs

@@ -0,0 +1,156 @@
+using System;
+using UnityEngine.Events;
+
+namespace UnityEngine.UI.Extensions
+{
+    [RequireComponent(typeof(RectTransform)), DisallowMultipleComponent]
+    [AddComponentMenu("UI/Extensions/Re-orderable list")]
+    public class ReorderableList : MonoBehaviour
+    {
+        [Tooltip("Child container with re-orderable items in a layout group")]
+        public LayoutGroup ContentLayout;
+
+        [Tooltip("Parent area to draw the dragged element on top of containers. Defaults to the root Canvas")]
+        public RectTransform DraggableArea;
+
+        [Tooltip("Can items be dragged from the container?")]
+        public bool IsDraggable = true;
+
+        [Tooltip("Should the draggable components be removed or cloned?")]
+        public bool CloneDraggedObject = false;
+
+        [Tooltip("Can new draggable items be dropped in to the container?")]
+        public bool IsDropable = true;
+
+        [Tooltip("Should dropped items displace a current item if the list is full?\n " +
+                 "Depending on the dropped items origin list, the displaced item may be added, dropped in space or deleted.")]
+        public bool IsDisplacable = false;
+
+        // This sets every item size (when being dragged over this list) to the current size of the first element of this list
+        [Tooltip("Should items being dragged over this list have their sizes equalized?")]
+        public bool EqualizeSizesOnDrag = false;
+
+        public int maxItems = int.MaxValue;
+
+
+        [Header("UI Re-orderable Events")] public ReorderableListHandler OnElementDropped = new ReorderableListHandler();
+        public ReorderableListHandler OnElementGrabbed = new ReorderableListHandler();
+        public ReorderableListHandler OnElementRemoved = new ReorderableListHandler();
+        public ReorderableListHandler OnElementAdded = new ReorderableListHandler();
+        public ReorderableListHandler OnElementDisplacedFrom = new ReorderableListHandler();
+        public ReorderableListHandler OnElementDisplacedTo = new ReorderableListHandler();
+        public ReorderableListHandler OnElementDisplacedFromReturned = new ReorderableListHandler();
+        public ReorderableListHandler OnElementDisplacedToReturned = new ReorderableListHandler();
+        public ReorderableListHandler OnElementDroppedWithMaxItems = new ReorderableListHandler();
+
+        private RectTransform _content;
+        private ReorderableListContent _listContent;
+
+        public RectTransform Content
+        {
+            get
+            {
+                if (_content == null)
+                {
+                    _content = ContentLayout.GetComponent<RectTransform>();
+                }
+
+                return _content;
+            }
+        }
+
+        Canvas GetCanvas()
+        {
+            Transform t = transform;
+            Canvas canvas = null;
+
+
+            int lvlLimit = 100;
+            int lvl = 0;
+
+            while (canvas == null && lvl < lvlLimit)
+            {
+                canvas = t.gameObject.GetComponent<Canvas>();
+                if (canvas == null)
+                {
+                    t = t.parent;
+                }
+
+                lvl++;
+            }
+
+            return canvas;
+        }
+
+        /// <summary>
+        /// Refresh related list content
+        /// </summary>
+        public void Refresh()
+        {
+            _listContent = ContentLayout.gameObject.GetOrAddComponent<ReorderableListContent>();
+            _listContent.Init(this);
+        }
+
+        private void Start()
+        {
+            if (ContentLayout == null)
+            {
+                Debug.LogError("是否确定不需要为列表:设置一个子LayoutGroup内容?  : " + name, gameObject);
+                return;
+            }
+
+            if (DraggableArea == null)
+            {
+              
+                DraggableArea =transform.root.GetComponent<RectTransform>();
+               // DraggableArea = transform.root.GetComponentInChildren<Canvas>().GetComponent<RectTransform>();
+            }
+
+            if (IsDropable && !GetComponent<Graphic>())
+            {
+                Debug.LogError("您需要有一个图形控件(例如图像)用于列表[" + name + "] 拖拽", gameObject);
+                return;
+            }
+
+            Refresh();
+        }
+
+
+        #region Nested type: ReorderableListEventStruct
+
+        [Serializable]
+        public struct ReorderableListEventStruct
+        {
+            public GameObject DroppedObject;
+            public int FromIndex;
+            public ReorderableList FromList;
+            public bool IsAClone;
+            public GameObject SourceObject;
+            public int ToIndex;
+            public ReorderableList ToList;
+
+            public void Cancel()
+            {
+                SourceObject.GetComponent<ReorderableListElement>().isValid = false;
+            }
+        }
+
+        #endregion
+
+
+        #region Nested type: ReorderableListHandler
+
+        [Serializable]
+        public class ReorderableListHandler : UnityEvent<ReorderableListEventStruct>
+        {
+        }
+
+        public void TestReOrderableListTarget(ReorderableListEventStruct item)
+        {
+            Debug.Log("Event Received");
+            Debug.Log("Hello World, is my item a clone? [" + item.IsAClone + "]");
+        }
+
+        #endregion
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableList.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 6b333d67eb08d464d823874f6a1666c2
+timeCreated: 1492560112
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 74 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListContent.cs

@@ -0,0 +1,74 @@
+/// Credit Ziboo
+/// Sourced from - http://forum.unity3d.com/threads/free-reorderable-list.364600/
+
+using System.Collections;
+using System.Collections.Generic;
+
+namespace UnityEngine.UI.Extensions
+{
+    [DisallowMultipleComponent]
+    public class ReorderableListContent : MonoBehaviour
+    {
+        private List<Transform> _cachedChildren;
+        private List<ReorderableListElement> _cachedListElement;
+        private ReorderableListElement _ele;
+        private ReorderableList _extList;
+        private RectTransform _rect;
+        private bool _started = false;
+
+        private void OnEnable()
+        {
+            if(_rect)StartCoroutine(RefreshChildren());
+        }
+
+
+        public void OnTransformChildrenChanged()
+        {
+            if(this.isActiveAndEnabled)StartCoroutine(RefreshChildren());
+        }
+
+        public void Init(ReorderableList extList)
+        {
+            if (_started) { StopCoroutine(RefreshChildren()); }
+
+            _extList = extList;
+            _rect = GetComponent<RectTransform>();
+            _cachedChildren = new List<Transform>();
+            _cachedListElement = new List<ReorderableListElement>();
+
+            StartCoroutine(RefreshChildren());
+            _started = true;
+        }
+
+        private IEnumerator RefreshChildren()
+        {
+            //Handle new children
+            for (int i = 0; i < _rect.childCount; i++)
+            {
+                if (_cachedChildren.Contains(_rect.GetChild(i)))
+                    continue;
+
+                //Get or Create ReorderableListElement
+                _ele = _rect.GetChild(i).gameObject.GetComponent<ReorderableListElement>() ??
+                       _rect.GetChild(i).gameObject.AddComponent<ReorderableListElement>();
+                _ele.Init(_extList);
+
+                _cachedChildren.Add(_rect.GetChild(i));
+                _cachedListElement.Add(_ele);
+            }
+
+            //HACK a little hack, if I don't wait one frame I don't have the right deleted children
+            yield return 0;
+
+            //Remove deleted child
+            for (int i = _cachedChildren.Count - 1; i >= 0; i--)
+            {
+                if (_cachedChildren[i] == null)
+                {
+                    _cachedChildren.RemoveAt(i);
+                    _cachedListElement.RemoveAt(i);
+                }
+            }
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListContent.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 252dd148b2c1dbe40b7d938a553e3caf
+timeCreated: 1446062045
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 29 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListDebug.cs

@@ -0,0 +1,29 @@
+/// Credit Ziboo
+/// Sourced from - http://forum.unity3d.com/threads/free-reorderable-list.364600/
+
+namespace UnityEngine.UI.Extensions
+{
+    public class ReorderableListDebug : MonoBehaviour
+    {
+        public Text DebugLabel;
+
+        void Awake()
+        {
+            foreach (var list in FindObjectsOfType<ReorderableList>())
+            {
+                list.OnElementDropped.AddListener(ElementDropped);
+            }
+        }
+
+        private void ElementDropped(ReorderableList.ReorderableListEventStruct droppedStruct)
+        {
+            DebugLabel.text = "";
+            DebugLabel.text += "Dropped Object: " + droppedStruct.DroppedObject.name + "\n";
+            DebugLabel.text += "Is Clone ?: " + droppedStruct.IsAClone + "\n";
+            if (droppedStruct.IsAClone)
+                DebugLabel.text += "Source Object: " + droppedStruct.SourceObject.name + "\n";
+            DebugLabel.text += string.Format("From {0} at Index {1} \n", droppedStruct.FromList.name, droppedStruct.FromIndex);
+            DebugLabel.text += string.Format("To {0} at Index {1} \n", droppedStruct.ToList == null ? "Empty space" : droppedStruct.ToList.name, droppedStruct.ToIndex);
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListDebug.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 86c224aef3e999140b78d1d7135ba33f
+timeCreated: 1446072313
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 563 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListElement.cs

@@ -0,0 +1,563 @@
+/// Credit Ziboo, Andrew Quesenberry 
+/// Sourced from - http://forum.unity3d.com/threads/free-reorderable-list.364600/
+/// Last Child Fix - https://bitbucket.org/SimonDarksideJ/unity-ui-extensions/issues/70/all-re-orderable-lists-cause-a-transform
+
+using System;
+using System.Collections.Generic;
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+
+    [RequireComponent(typeof(RectTransform), typeof(LayoutElement))]
+    public class ReorderableListElement : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
+    {
+        [Tooltip("这个元素可以拖动吗?")]
+        [SerializeField]
+        public bool IsGrabbable = true;
+
+        [Tooltip("这个元素可以被转移到另一个listelement被拖动吗?  ")]
+        [SerializeField]
+        private bool _isTransferable = true;
+
+        [Tooltip("这个元素能被放到空间中吗?")]
+        [SerializeField]
+        private bool isDroppableInSpace = false;
+
+
+        public bool IsTransferable
+        {
+            get { return _isTransferable; }
+            set 
+            {
+                _canvasGroup = gameObject.GetOrAddComponent<CanvasGroup>();
+                _canvasGroup.blocksRaycasts = value;
+                _isTransferable = value; 
+            }
+        }
+
+        private readonly List<RaycastResult> _raycastResults = new List<RaycastResult>();
+        private ReorderableList _currentReorderableListRaycasted;
+
+        private int _fromIndex;
+        private RectTransform _draggingObject;
+        private LayoutElement _draggingObjectLE;
+        private Vector2 _draggingObjectOriginalSize;
+
+        private RectTransform _fakeElement;
+        private LayoutElement _fakeElementLE;
+
+        private int _displacedFromIndex;
+        private RectTransform _displacedObject;
+        private LayoutElement _displacedObjectLE;
+        private Vector2 _displacedObjectOriginalSize;
+        private ReorderableList _displacedObjectOriginList;
+
+        private bool _isDragging;
+        private RectTransform _rect;
+        private ReorderableList _reorderableList;
+        private CanvasGroup _canvasGroup;
+        internal bool isValid;
+
+        public Action OnBeginDragAction;
+
+        #region IBeginDragHandler Members
+
+        public void OnBeginDrag(PointerEventData eventData)
+        {
+            if (!_canvasGroup) { _canvasGroup = gameObject.GetOrAddComponent<CanvasGroup>(); }
+            _canvasGroup.blocksRaycasts = false;
+            isValid = true;
+            if (_reorderableList == null)
+                return;
+
+            //Can't drag, return...
+            if (!_reorderableList.IsDraggable || !this.IsGrabbable)
+            {
+                _draggingObject = null;
+                return;
+            }
+
+            //If not CloneDraggedObject just set draggingObject to this gameobject
+            if (_reorderableList.CloneDraggedObject == false)
+            {
+                _draggingObject = _rect;
+                _fromIndex = _rect.GetSiblingIndex();
+                _displacedFromIndex = -1;
+                //Send OnElementRemoved Event
+                if (_reorderableList.OnElementRemoved != null)
+                {
+                    _reorderableList.OnElementRemoved.Invoke(new ReorderableList.ReorderableListEventStruct
+                        {
+                            DroppedObject = _draggingObject.gameObject,
+                            IsAClone = _reorderableList.CloneDraggedObject,
+                            SourceObject = _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject,
+                            FromList = _reorderableList,
+                            FromIndex = _fromIndex,
+                        });
+                }
+                if (isValid == false)
+                {
+                    _draggingObject = null;
+                    return;
+                }
+            }
+            else
+            {
+                //Else Duplicate
+                GameObject clone = (GameObject)Instantiate(gameObject);
+                _draggingObject = clone.GetComponent<RectTransform>();
+            }
+
+            //Put _dragging object into the dragging area
+            _draggingObjectOriginalSize = gameObject.GetComponent<RectTransform>().rect.size;
+            _draggingObjectLE = _draggingObject.GetComponent<LayoutElement>();
+            _draggingObject.SetParent(_reorderableList.DraggableArea, true);
+            _draggingObject.SetAsLastSibling();
+            _reorderableList.Refresh();
+
+            //Create a fake element for previewing placement
+            _fakeElement = new GameObject("Fake").AddComponent<RectTransform>();
+            _fakeElementLE = _fakeElement.gameObject.AddComponent<LayoutElement>();
+
+            RefreshSizes();
+            OnBeginDragAction?.Invoke();
+            //Send OnElementGrabbed Event
+            if (_reorderableList.OnElementGrabbed != null)
+            {
+                _reorderableList.OnElementGrabbed.Invoke(new ReorderableList.ReorderableListEventStruct
+                    {
+                        DroppedObject = _draggingObject.gameObject,
+                        IsAClone = _reorderableList.CloneDraggedObject,
+                        SourceObject = _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject,
+                        FromList = _reorderableList,
+                        FromIndex = _fromIndex,
+                    });
+
+                if (!isValid)
+                {
+                    CancelDrag();
+                    return;
+                }
+            }
+
+            _isDragging = true;
+        }
+
+        #endregion
+
+
+        #region IDragHandler Members
+
+        public void OnDrag(PointerEventData eventData)
+        {
+            if (!_isDragging)
+                return;
+            if (!isValid)
+            {
+                CancelDrag();
+                return;
+            }
+            //Set dragging object on cursor
+          //  var canvas = _draggingObject.GetComponentInParent<Canvas>();
+            var canvas =_draggingObject.GetComponentInParent<Canvas>();
+            Vector3 worldPoint;
+            RectTransformUtility.ScreenPointToWorldPointInRectangle(canvas.GetComponent<RectTransform>(), eventData.position,
+                canvas.renderMode != RenderMode.ScreenSpaceOverlay ? canvas.worldCamera : null, out worldPoint);
+            _draggingObject.position = worldPoint;
+
+            ReorderableList _oldReorderableListRaycasted = _currentReorderableListRaycasted;
+
+            //检查光标下的所有内容以找到 ReorderableList
+            EventSystem.current.RaycastAll(eventData, _raycastResults);
+            for (int i = 0; i < _raycastResults.Count; i++)
+            {
+                _currentReorderableListRaycasted = _raycastResults[i].gameObject.GetComponent<ReorderableList>();
+                if (_currentReorderableListRaycasted != null)
+                {
+                    break;
+                }
+            }
+
+            //如果没有找到或列表不可删除,将假元素放在外面
+            if (_currentReorderableListRaycasted == null || _currentReorderableListRaycasted.IsDropable == false
+//                || (_oldReorderableListRaycasted != _reorderableList && !IsTransferable)
+                || ((_fakeElement.parent == _currentReorderableListRaycasted.Content 
+                    ? _currentReorderableListRaycasted.Content.childCount - 1 
+                    : _currentReorderableListRaycasted.Content.childCount) >= _currentReorderableListRaycasted.maxItems && !_currentReorderableListRaycasted.IsDisplacable)
+                || _currentReorderableListRaycasted.maxItems <= 0)
+            {
+                RefreshSizes();
+                _fakeElement.transform.SetParent(_reorderableList.DraggableArea, false);
+                // revert the displaced element when not hovering over its list
+                if (_displacedObject != null)
+                {
+                    revertDisplacedElement();
+                }
+            }
+            //否则找到列表中的最佳位置并将假元素放在正确的索引上
+            else
+            {
+                if (_currentReorderableListRaycasted.Content.childCount < _currentReorderableListRaycasted.maxItems && _fakeElement.parent != _currentReorderableListRaycasted.Content)
+                {
+                    _fakeElement.SetParent(_currentReorderableListRaycasted.Content, false);
+                }
+
+                float minDistance = float.PositiveInfinity;
+                int targetIndex = 0;
+                float dist = 0;
+                for (int j = 0; j < _currentReorderableListRaycasted.Content.childCount; j++)
+                {
+                    var c = _currentReorderableListRaycasted.Content.GetChild(j).GetComponent<RectTransform>();
+
+                    if (_currentReorderableListRaycasted.ContentLayout is VerticalLayoutGroup)
+                        dist = Mathf.Abs(c.position.y - worldPoint.y);
+                    else if (_currentReorderableListRaycasted.ContentLayout is HorizontalLayoutGroup)
+                        dist = Mathf.Abs(c.position.x - worldPoint.x);
+                    else if (_currentReorderableListRaycasted.ContentLayout is GridLayoutGroup)
+                        dist = (Mathf.Abs(c.position.x - worldPoint.x) + Mathf.Abs(c.position.y - worldPoint.y));
+
+                    if (dist < minDistance)
+                    {
+                        minDistance = dist;
+                        targetIndex = j;
+                    }
+                }
+                if ((_currentReorderableListRaycasted != _oldReorderableListRaycasted || targetIndex != _displacedFromIndex)
+                    && _currentReorderableListRaycasted.Content.childCount == _currentReorderableListRaycasted.maxItems)
+                {
+                    Transform toDisplace = _currentReorderableListRaycasted.Content.GetChild(targetIndex);
+                    if (_displacedObject != null)
+                    {
+                        revertDisplacedElement();
+                        if (_currentReorderableListRaycasted.Content.childCount > _currentReorderableListRaycasted.maxItems)
+                        {
+                            displaceElement(targetIndex, toDisplace);
+                        }
+                    }
+                    else if (_fakeElement.parent != _currentReorderableListRaycasted.Content)
+                    {
+                        _fakeElement.SetParent(_currentReorderableListRaycasted.Content, false);
+                        displaceElement(targetIndex, toDisplace);
+                    }
+                }
+                RefreshSizes();
+                _fakeElement.gameObject.SetActive(false);
+                _fakeElement.SetSiblingIndex(targetIndex);
+                _fakeElement.gameObject.SetActive(true);
+
+            }
+        }
+
+        #endregion
+
+
+        #region Displacement
+
+        private void displaceElement(int targetIndex, Transform displaced)
+        {
+            _displacedFromIndex = targetIndex;
+            _displacedObjectOriginList = _currentReorderableListRaycasted;
+            _displacedObject = displaced.GetComponent<RectTransform>();
+            _displacedObjectLE = _displacedObject.GetComponent<LayoutElement>();
+            _displacedObjectOriginalSize = _displacedObject.rect.size;
+
+            var args = new ReorderableList.ReorderableListEventStruct
+            {
+                DroppedObject = _displacedObject.gameObject,
+                FromList = _currentReorderableListRaycasted,
+                FromIndex = targetIndex,
+            };
+
+
+            int c = _fakeElement.parent == _reorderableList.Content 
+                ? _reorderableList.Content.childCount - 1 
+                : _reorderableList.Content.childCount;
+
+            if (_reorderableList.IsDropable && c < _reorderableList.maxItems && _displacedObject.GetComponent<ReorderableListElement>().IsTransferable)
+            {
+                _displacedObjectLE.preferredWidth = _draggingObjectOriginalSize.x;
+                _displacedObjectLE.preferredHeight = _draggingObjectOriginalSize.y;
+                _displacedObject.SetParent(_reorderableList.Content, false);
+                _displacedObject.rotation = _reorderableList.transform.rotation;
+                _displacedObject.SetSiblingIndex(_fromIndex);
+                // Force refreshing both lists because otherwise we get inappropriate FromList in ReorderableListEventStruct 
+                _reorderableList.Refresh();
+                _currentReorderableListRaycasted.Refresh();
+
+                args.ToList = _reorderableList;
+                args.ToIndex = _fromIndex;
+                _reorderableList.OnElementDisplacedTo.Invoke(args);
+                _reorderableList.OnElementAdded.Invoke(args);
+            }
+            else if (_displacedObject.GetComponent<ReorderableListElement>().isDroppableInSpace)
+            {
+                _displacedObject.SetParent(_currentReorderableListRaycasted.DraggableArea, true);
+                _currentReorderableListRaycasted.Refresh();
+                _displacedObject.position += new Vector3(_draggingObjectOriginalSize.x / 2, _draggingObjectOriginalSize.y / 2, 0);
+            }
+            else
+            {
+                _displacedObject.SetParent(null, true);
+                _displacedObjectOriginList.Refresh();
+                _displacedObject.gameObject.SetActive(false);
+            }
+            _displacedObjectOriginList.OnElementDisplacedFrom.Invoke(args);
+            _reorderableList.OnElementRemoved.Invoke(args);
+        }
+
+        private void revertDisplacedElement()
+        {
+            var args = new ReorderableList.ReorderableListEventStruct
+            {
+                DroppedObject = _displacedObject.gameObject,
+                FromList = _displacedObjectOriginList,
+                FromIndex = _displacedFromIndex,
+            };
+            if (_displacedObject.parent != null)
+            {
+                args.ToList = _reorderableList;
+                args.ToIndex = _fromIndex;
+            }
+
+            _displacedObjectLE.preferredWidth = _displacedObjectOriginalSize.x;
+            _displacedObjectLE.preferredHeight = _displacedObjectOriginalSize.y;
+            _displacedObject.SetParent(_displacedObjectOriginList.Content, false);
+            _displacedObject.rotation = _displacedObjectOriginList.transform.rotation;
+            _displacedObject.SetSiblingIndex(_displacedFromIndex);
+            _displacedObject.gameObject.SetActive(true);
+
+            // Force refreshing both lists because otherwise we get inappropriate FromList in ReorderableListEventStruct 
+            _reorderableList.Refresh();
+            _displacedObjectOriginList.Refresh();
+
+            if (args.ToList != null)
+            {
+                _reorderableList.OnElementDisplacedToReturned.Invoke(args);
+                _reorderableList.OnElementRemoved.Invoke(args);
+            }
+            _displacedObjectOriginList.OnElementDisplacedFromReturned.Invoke(args);
+            _displacedObjectOriginList.OnElementAdded.Invoke(args);
+
+            _displacedFromIndex = -1;
+            _displacedObjectOriginList = null;
+            _displacedObject = null;
+            _displacedObjectLE = null;
+
+        }
+
+
+        public void finishDisplacingElement()
+        {
+            if (_displacedObject.parent == null)
+            {
+                Destroy(_displacedObject.gameObject);
+            }
+            _displacedFromIndex = -1;
+            _displacedObjectOriginList = null;
+            _displacedObject = null;
+            _displacedObjectLE = null;
+        }
+
+        #endregion
+
+
+        #region IEndDragHandler Members
+
+        public Action OnEndDragAction;
+        public void OnEndDrag(PointerEventData eventData)
+        {
+            _isDragging = false;
+
+            if (_draggingObject != null)
+            {
+             
+                //If we have a ReorderableList that is dropable
+                //Put the dragged object into the content and at the right index
+                if (_currentReorderableListRaycasted != null && _fakeElement.parent == _currentReorderableListRaycasted.Content)
+                {
+                    var args = new ReorderableList.ReorderableListEventStruct
+                    {
+                        DroppedObject = _draggingObject.gameObject,
+                        IsAClone = _reorderableList.CloneDraggedObject,
+                        SourceObject = _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject,
+                        FromList = _reorderableList,
+                        FromIndex = _fromIndex,
+                        ToList = _currentReorderableListRaycasted,
+                        ToIndex = _fakeElement.GetSiblingIndex()
+                    };
+                    //发送元素拖拽结束事件
+                    if (_reorderableList && _reorderableList.OnElementDropped != null)
+                    {
+                        _reorderableList.OnElementDropped.Invoke(args);
+                    }
+                    if (!isValid)
+                    {
+                        CancelDrag();
+                        return;
+                    }
+                    RefreshSizes();
+                    _draggingObject.SetParent(_currentReorderableListRaycasted.Content, false);
+                    _draggingObject.rotation = _currentReorderableListRaycasted.transform.rotation;
+                    _draggingObject.SetSiblingIndex(_fakeElement.GetSiblingIndex());
+
+                    //If the item is transferable, it can be dragged out again
+                    if (IsTransferable)
+                    {
+                        var cg = _draggingObject.GetComponent<CanvasGroup>();
+                        cg.blocksRaycasts = true;
+                    }
+                    // Force refreshing both lists because otherwise we get inappropriate FromList in ReorderableListEventStruct 
+                    _reorderableList.Refresh();
+                    _currentReorderableListRaycasted.Refresh();
+
+                    _reorderableList.OnElementAdded.Invoke(args);
+            
+                    if (_displacedObject != null)
+                    {
+                        finishDisplacingElement();
+                    }
+
+                    if (!isValid)
+                        throw new Exception("It's too late to cancel the Transfer! Do so in OnElementDropped!");
+                }
+                
+                else
+                {
+                    //We don't have an ReorderableList
+                    if (this.isDroppableInSpace)
+                    {
+                        _reorderableList.OnElementDropped.Invoke(new ReorderableList.ReorderableListEventStruct
+                            {
+                                DroppedObject = _draggingObject.gameObject,
+                                IsAClone = _reorderableList.CloneDraggedObject,
+                                SourceObject =
+                                    _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject,
+                                FromList = _reorderableList,
+                                FromIndex = _fromIndex
+                            });
+                    }
+                    else
+                    {
+                        CancelDrag();
+                    }
+                    
+                    //If there is no more room for the element in the target list, notify it (OnElementDroppedWithMaxItems event) 
+                    if (_currentReorderableListRaycasted != null)
+                    {
+                        if ((_currentReorderableListRaycasted.Content.childCount >=
+                             _currentReorderableListRaycasted.maxItems &&
+                             !_currentReorderableListRaycasted.IsDisplacable)
+                            || _currentReorderableListRaycasted.maxItems <= 0)
+                        {
+                            GameObject o = _draggingObject.gameObject;
+                            _reorderableList.OnElementDroppedWithMaxItems.Invoke(
+                                new ReorderableList.ReorderableListEventStruct
+                                {
+                                    DroppedObject = o,
+                                    IsAClone = _reorderableList.CloneDraggedObject,
+                                    SourceObject = _reorderableList.CloneDraggedObject ? gameObject : o,
+                                    FromList = _reorderableList,
+                                    ToList = _currentReorderableListRaycasted,
+                                    FromIndex = _fromIndex
+                                });
+                        } 
+                    }
+                    
+                }
+            }
+
+            //Delete fake element
+            if (_fakeElement != null)
+            {
+                Destroy(_fakeElement.gameObject);
+             
+                _fakeElement = null;
+            }
+            _canvasGroup.blocksRaycasts = true;
+            OnEndDragAction?.Invoke();
+        }
+
+        #endregion
+
+
+        void CancelDrag()
+        {
+            _isDragging = false;
+            //If it's a clone, delete it
+            if (_reorderableList.CloneDraggedObject)
+            {
+                Destroy(_draggingObject.gameObject);
+            }
+            //Else replace the draggedObject to his first place
+            else
+            {
+                RefreshSizes();
+                _draggingObject.SetParent(_reorderableList.Content, false);
+                _draggingObject.rotation = _reorderableList.Content.transform.rotation;
+                _draggingObject.SetSiblingIndex(_fromIndex);
+
+
+                var args = new ReorderableList.ReorderableListEventStruct
+                {
+                    DroppedObject = _draggingObject.gameObject,
+                    IsAClone = _reorderableList.CloneDraggedObject,
+                    SourceObject = _reorderableList.CloneDraggedObject ? gameObject : _draggingObject.gameObject,
+                    FromList = _reorderableList,
+                    FromIndex = _fromIndex,
+                    ToList = _reorderableList,
+                    ToIndex = _fromIndex
+                };
+
+                _reorderableList.Refresh();
+
+                _reorderableList.OnElementAdded.Invoke(args);
+
+                if (!isValid)
+                    throw new Exception("Transfer is already Canceled.");
+
+            }
+
+            //Delete fake element
+            if (_fakeElement != null)
+            {
+                Destroy(_fakeElement.gameObject);
+                _fakeElement = null;
+            }
+            if (_displacedObject != null)
+            {
+                revertDisplacedElement();
+            }
+            _canvasGroup.blocksRaycasts = true;
+        }
+
+        private void RefreshSizes()
+        {
+            Vector2 size = _draggingObjectOriginalSize;
+
+            if (_currentReorderableListRaycasted != null
+                && _currentReorderableListRaycasted.IsDropable
+                && _currentReorderableListRaycasted.Content.childCount > 0
+                && _currentReorderableListRaycasted.EqualizeSizesOnDrag)
+            {
+                var firstChild = _currentReorderableListRaycasted.Content.GetChild(0);
+                if (firstChild != null)
+                {
+                    size = firstChild.GetComponent<RectTransform>().rect.size;
+                }
+            }
+
+            _draggingObject.sizeDelta = size;
+            _fakeElementLE.preferredHeight = _draggingObjectLE.preferredHeight = size.y;
+            _fakeElementLE.preferredWidth = _draggingObjectLE.preferredWidth = size.x;
+            _fakeElement.GetComponent<RectTransform>().sizeDelta = size;
+        }
+
+        public void Init(ReorderableList reorderableList)
+        {
+            _reorderableList = reorderableList;
+            _rect = GetComponent<RectTransform>();
+            _canvasGroup = gameObject.GetOrAddComponent<CanvasGroup>();
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/ReorderableList/ReorderableListElement.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 916e98f1b982a9a4082fcc45c87b66c5
+timeCreated: 1492560112
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: c4c2c5317e2b50f42b0302414577a62d
+folderAsset: yes
+timeCreated: 1440843775
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 64 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/RescaleDragPanel.cs

@@ -0,0 +1,64 @@
+/// Credit .entity
+/// Sourced from - http://forum.unity3d.com/threads/rescale-panel.309226/
+
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    [AddComponentMenu("UI/Extensions/RescalePanels/RescaleDragPanel")]
+    public class RescaleDragPanel : MonoBehaviour, IPointerDownHandler, IDragHandler
+    {
+        private Vector2 pointerOffset;
+        private RectTransform canvasRectTransform;
+        private RectTransform panelRectTransform;
+
+        private Transform goTransform;
+
+        void Awake()
+        {
+            Canvas canvas = GetComponentInParent<Canvas>();
+            if (canvas != null)
+            {
+                canvasRectTransform = canvas.transform as RectTransform;
+                panelRectTransform = transform.parent as RectTransform;
+                goTransform = transform.parent;
+            }
+        }
+
+        public void OnPointerDown(PointerEventData data)
+        {
+            panelRectTransform.SetAsLastSibling();
+            RectTransformUtility.ScreenPointToLocalPointInRectangle(panelRectTransform, data.position, data.pressEventCamera, out pointerOffset);
+        }
+
+        public void OnDrag(PointerEventData data)
+        {
+            if (panelRectTransform == null)
+                return;
+
+            Vector2 pointerPosition = ClampToWindow(data);
+
+            Vector2 localPointerPosition;
+            if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
+                canvasRectTransform, pointerPosition, data.pressEventCamera, out localPointerPosition
+                ))
+            {
+                panelRectTransform.localPosition = localPointerPosition - new Vector2(pointerOffset.x * goTransform.localScale.x, pointerOffset.y * goTransform.localScale.y);
+            }
+        }
+
+        Vector2 ClampToWindow(PointerEventData data)
+        {
+            Vector2 rawPointerPosition = data.position;
+
+            Vector3[] canvasCorners = new Vector3[4];
+            canvasRectTransform.GetWorldCorners(canvasCorners);
+
+            float clampedX = Mathf.Clamp(rawPointerPosition.x, canvasCorners[0].x, canvasCorners[2].x);
+            float clampedY = Mathf.Clamp(rawPointerPosition.y, canvasCorners[0].y, canvasCorners[2].y);
+
+            Vector2 newPointerPosition = new Vector2(clampedX, clampedY);
+            return newPointerPosition;
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/RescaleDragPanel.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: c210a6e68020b4349a4020e7da57826e
+timeCreated: 1440843816
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 62 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/RescalePanel.cs

@@ -0,0 +1,62 @@
+/// Credit .entity
+/// Sourced from - http://forum.unity3d.com/threads/rescale-panel.309226/
+
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    [AddComponentMenu("UI/Extensions/RescalePanels/RescalePanel")]
+    public class RescalePanel : MonoBehaviour, IPointerDownHandler, IDragHandler
+    {
+        public Vector2 minSize;
+        public Vector2 maxSize;
+
+        private RectTransform rectTransform;
+        private Transform goTransform;
+        private Vector2 currentPointerPosition;
+        private Vector2 previousPointerPosition;
+
+        private RectTransform thisRectTransform;
+        Vector2 sizeDelta;
+
+        void Awake()
+        {
+            rectTransform = transform.parent.GetComponent<RectTransform>();
+            goTransform = transform.parent;
+
+            thisRectTransform = GetComponent<RectTransform>();
+            sizeDelta = thisRectTransform.sizeDelta;
+        }
+
+        public void OnPointerDown(PointerEventData data)
+        {
+            rectTransform.SetAsLastSibling();
+            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, data.position, data.pressEventCamera, out previousPointerPosition);
+        }
+
+        public void OnDrag(PointerEventData data)
+        {
+            if (rectTransform == null)
+                return;
+
+            Vector3 scaleDelta = goTransform.localScale;
+
+            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, data.position, data.pressEventCamera, out currentPointerPosition);
+            Vector2 resizeValue = currentPointerPosition - previousPointerPosition;
+
+            scaleDelta += new Vector3(-resizeValue.y * 0.001f, -resizeValue.y * 0.001f, 0f);
+            scaleDelta = new Vector3(
+                Mathf.Clamp(scaleDelta.x, minSize.x, maxSize.x),
+                Mathf.Clamp(scaleDelta.y, minSize.y, maxSize.y),
+                1
+                );
+
+            goTransform.localScale = scaleDelta;
+
+            previousPointerPosition = currentPointerPosition;
+            float resizeDeltaValue = sizeDelta.x / goTransform.localScale.x;
+            Vector2 newSizeDelta = new Vector2(resizeDeltaValue, resizeDeltaValue);
+            thisRectTransform.sizeDelta = newSizeDelta;
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/RescalePanel.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ff46b67332ade77459ea86ba20638d24
+timeCreated: 1440843795
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 60 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/ResizePanel.cs

@@ -0,0 +1,60 @@
+/// Credit .entity
+/// Sourced from - http://forum.unity3d.com/threads/rescale-panel.309226/
+
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    [AddComponentMenu("UI/Extensions/RescalePanels/ResizePanel")]
+    public class ResizePanel : MonoBehaviour, IPointerDownHandler, IDragHandler
+    {
+        public Vector2 minSize;
+        public Vector2 maxSize;
+
+        private RectTransform rectTransform;
+        private Vector2 currentPointerPosition;
+        private Vector2 previousPointerPosition;
+
+        private float ratio;
+
+
+        void Awake()
+        {
+            rectTransform = transform.parent.GetComponent<RectTransform>();
+            float originalWidth;
+            float originalHeight;
+            originalWidth = rectTransform.rect.width;
+            originalHeight = rectTransform.rect.height;
+            ratio = originalHeight / originalWidth;
+            minSize = new Vector2(0.1f * originalWidth, 0.1f * originalHeight);
+            maxSize = new Vector2(10f * originalWidth, 10f * originalHeight);
+        }
+
+        public void OnPointerDown(PointerEventData data)
+        {
+            rectTransform.SetAsLastSibling();
+            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, data.position, data.pressEventCamera, out previousPointerPosition);
+        }
+
+        public void OnDrag(PointerEventData data)
+        {
+            if (rectTransform == null)
+                return;
+
+            Vector2 sizeDelta = rectTransform.sizeDelta;
+
+            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, data.position, data.pressEventCamera, out currentPointerPosition);
+            Vector2 resizeValue = currentPointerPosition - previousPointerPosition;
+
+            sizeDelta += new Vector2(resizeValue.x, ratio * resizeValue.x);
+            sizeDelta = new Vector2(
+                Mathf.Clamp(sizeDelta.x, minSize.x, maxSize.x),
+                Mathf.Clamp(sizeDelta.y, minSize.y, maxSize.y)
+                );
+
+            rectTransform.sizeDelta = sizeDelta;
+
+            previousPointerPosition = currentPointerPosition;
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/RescalingPanels/ResizePanel.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: db83442065d59344c9bf6ffa63a23777
+timeCreated: 1440843837
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 236 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Segment.cs

@@ -0,0 +1,236 @@
+/// Credit David Gileadi
+/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/12
+
+using System;
+using System.Collections;
+using UnityEngine.Events;
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    [AddComponentMenu("UI/Extensions/Segmented Control/Segment")]
+    [RequireComponent(typeof(Selectable))]
+    public class Segment :
+        UIBehaviour,
+        IPointerClickHandler,
+        ISubmitHandler,
+        IPointerEnterHandler, IPointerExitHandler,
+        IPointerDownHandler, IPointerUpHandler,
+        ISelectHandler, IDeselectHandler
+    {
+        internal int index;
+        internal SegmentedControl segmentedControl;
+
+        internal bool leftmost
+        {
+            get { return index == 0; }
+        }
+        internal bool rightmost
+        {
+            get { return index == segmentedControl.segments.Length - 1; }
+        }
+
+        public bool selected
+        {
+            get { return segmentedControl.selectedSegment == this.button; }
+            set { SetSelected(value); }
+        }
+
+        internal Selectable button
+        {
+            get { return GetComponent<Selectable>(); }
+        }
+
+        internal Sprite cutSprite;
+
+        protected Segment()
+        { }
+
+        protected override void Start()
+        {
+            StartCoroutine(DelayedInit());
+        }
+
+        IEnumerator DelayedInit()
+        {
+            yield return null;
+            yield return null;
+
+            button.image.overrideSprite = cutSprite;
+            if (selected)
+                MaintainSelection();
+        }
+
+        public virtual void OnPointerClick(PointerEventData eventData)
+        {
+            if (eventData.button != PointerEventData.InputButton.Left)
+                return;
+
+            selected = true;
+        }
+
+        public virtual void OnPointerEnter(PointerEventData eventData)
+        {
+            MaintainSelection();
+        }
+
+        public virtual void OnPointerExit(PointerEventData eventData)
+        {
+            MaintainSelection();
+        }
+
+        public virtual void OnPointerDown(PointerEventData eventData)
+        {
+            MaintainSelection();
+        }
+
+        public virtual void OnPointerUp(PointerEventData eventData)
+        {
+            MaintainSelection();
+        }
+
+        public virtual void OnSelect(BaseEventData eventData)
+        {
+            MaintainSelection();
+        }
+
+        public virtual void OnDeselect(BaseEventData eventData)
+        {
+            MaintainSelection();
+        }
+
+        protected override void OnEnable()
+        {
+            base.OnEnable();
+            if (segmentedControl)
+                MaintainSelection();
+        }
+
+        public virtual void OnSubmit(BaseEventData eventData)
+        {
+            selected = true;
+        }
+
+        private void SetSelected(bool value)
+        {
+            if (value && button.IsActive() && button.IsInteractable())
+            {
+                if (segmentedControl.selectedSegment == this.button)
+                {
+                    if (segmentedControl.allowSwitchingOff)
+                    {
+                        Deselect();
+                    }
+                    else
+                    {
+                        MaintainSelection();
+                    }
+                }
+                else
+                {
+                    if (segmentedControl.selectedSegment)
+                    {
+                        var segment = segmentedControl.selectedSegment.GetComponent<Segment>();
+                        segmentedControl.selectedSegment = null;
+                        if (segment)
+                        {
+                            segment.TransitionButton();
+                        }
+                    }
+
+                    segmentedControl.selectedSegment = this.button;
+                    TransitionButton();
+                    segmentedControl.onValueChanged.Invoke(index);
+                }
+            }
+            else if (segmentedControl.selectedSegment == this.button)
+            {
+                Deselect();
+            }
+        }
+
+        private void Deselect()
+        {
+            segmentedControl.selectedSegment = null;
+            TransitionButton();
+            segmentedControl.onValueChanged.Invoke(-1);
+        }
+
+        void MaintainSelection()
+        {
+            if (button != segmentedControl.selectedSegment)
+                return;
+
+            TransitionButton(true);
+        }
+
+        internal void TransitionButton()
+        {
+            TransitionButton(false);
+        }
+
+        internal void TransitionButton(bool instant)
+        {
+            Color tintColor = selected ? button.colors.pressedColor : button.colors.normalColor;
+            Color textColor = selected ? button.colors.normalColor : button.colors.pressedColor;
+            Sprite transitionSprite = selected ? button.spriteState.pressedSprite : cutSprite;
+            string triggerName = selected ? button.animationTriggers.pressedTrigger : button.animationTriggers.normalTrigger;
+
+            switch (button.transition)
+            {
+                case Selectable.Transition.ColorTint:
+                    button.image.overrideSprite = cutSprite;
+                    StartColorTween(tintColor * button.colors.colorMultiplier, instant);
+                    ChangeTextColor(textColor * button.colors.colorMultiplier);
+                    break;
+                case Selectable.Transition.SpriteSwap:
+                    if (transitionSprite != cutSprite)
+                        transitionSprite = SegmentedControl.CutSprite(transitionSprite, leftmost, rightmost);
+                    DoSpriteSwap(transitionSprite);
+                    break;
+                case Selectable.Transition.Animation:
+                    button.image.overrideSprite = cutSprite;
+                    TriggerAnimation(triggerName);
+                    break;
+            }
+        }
+
+        void StartColorTween(Color targetColor, bool instant)
+        {
+            if (button.targetGraphic == null)
+                return;
+
+            button.targetGraphic.CrossFadeColor(targetColor, instant ? 0f : button.colors.fadeDuration, true, true);
+        }
+
+        void ChangeTextColor(Color targetColor)
+        {
+            var text = GetComponentInChildren<Text>();
+            if (!text)
+                return;
+
+            text.color = targetColor;
+        }
+
+        void DoSpriteSwap(Sprite newSprite)
+        {
+            if (button.image == null)
+                return;
+
+            button.image.overrideSprite = newSprite;
+        }
+
+        void TriggerAnimation(string triggername)
+        {
+            if (button.animator == null || !button.animator.isActiveAndEnabled || !button.animator.hasBoundPlayables || string.IsNullOrEmpty(triggername))
+                return;
+
+            button.animator.ResetTrigger(button.animationTriggers.normalTrigger);
+            button.animator.ResetTrigger(button.animationTriggers.pressedTrigger);
+            button.animator.ResetTrigger(button.animationTriggers.highlightedTrigger);
+            button.animator.ResetTrigger(button.animationTriggers.disabledTrigger);
+
+            button.animator.SetTrigger(triggername);
+        }
+    }
+}

+ 12 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/Segment.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b8ea9937637d64c6da52723c68267703
+timeCreated: 1503449008
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 245 - 0
Assets/Scripts/GameUI/UIExtensions/Scripts/Controls/SegmentedControl.cs

@@ -0,0 +1,245 @@
+/// Credit David Gileadi
+/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/12
+
+using System;
+using System.Collections;
+using UnityEngine.Events;
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI.Extensions
+{
+    // Segmented control, like a group of buttons
+    [AddComponentMenu("UI/Extensions/Segmented Control/Segmented Control")]
+    [RequireComponent(typeof(RectTransform))]
+    public class SegmentedControl : UIBehaviour
+    {
+        private Selectable[] m_segments;
+        [SerializeField]
+        [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")]
+        private Graphic m_separator;
+        private float m_separatorWidth = 0;
+        [SerializeField]
+        [Tooltip("When True, it allows each button to be toggled on/off")]
+        private bool m_allowSwitchingOff = false;
+        [SerializeField]
+        [Tooltip("The selected default for the control (zero indexed array)")]
+        private int m_selectedSegmentIndex = -1;
+        // Event delegates triggered on click.
+        [SerializeField]
+        [Tooltip("Event to fire once the selection has been changed")]
+        private SegmentSelectedEvent m_onValueChanged = new SegmentSelectedEvent();
+
+        internal Selectable selectedSegment;
+
+        protected float SeparatorWidth
+        {
+            get
+            {
+                if (m_separatorWidth == 0 && separator)
+                {
+                    m_separatorWidth = separator.rectTransform.rect.width;
+                    var image = separator.GetComponent<Image>();
+                    if (image)
+                        m_separatorWidth /= image.pixelsPerUnit;
+                }
+                return m_separatorWidth;
+            }
+        }
+
+        [Serializable]
+        public class SegmentSelectedEvent : UnityEvent<int> { }
+
+        public Selectable[] segments
+        {
+            get
+            {
+                if (m_segments == null || m_segments.Length == 0)
+                {
+                    m_segments = GetChildSegments();
+                }
+                return m_segments;
+            }
+        }
+
+        public Graphic separator { get { return m_separator; } set { m_separator = value; m_separatorWidth = 0; LayoutSegments(); } }
+
+        public bool allowSwitchingOff { get { return m_allowSwitchingOff; } set { m_allowSwitchingOff = value; } }
+
+        public int selectedSegmentIndex
+        {
+            get { return Array.IndexOf(segments, selectedSegment); }
+            set
+            {
+                value = Math.Max(value, -1);
+                value = Math.Min(value, segments.Length - 1);
+
+                if (m_selectedSegmentIndex == value)
+                {
+                    return;
+                }
+
+                m_selectedSegmentIndex = value;
+
+                if (selectedSegment)
+                {
+                    var segment = selectedSegment.GetComponent<Segment>();
+                    if (segment)
+                    {
+                        segment.selected = false;
+                    }
+                    selectedSegment = null;
+                }
+
+                if (value != -1)
+                {
+                    selectedSegment = segments[value];
+                    var segment = selectedSegment.GetComponent<Segment>();
+                    if (segment)
+                    {
+                        segment.selected = true;
+                    }
+                }
+            }
+        }
+
+        public SegmentSelectedEvent onValueChanged
+        {
+            get { return m_onValueChanged; }
+            set { m_onValueChanged = value; }
+        }
+
+        protected SegmentedControl()
+        { }
+
+        protected override void Start()
+        {
+            base.Start();
+
+            if (isActiveAndEnabled)
+                StartCoroutine(DelayedInit());
+        }
+
+        protected override void OnEnable()
+        {
+            StartCoroutine(DelayedInit());
+        }
+
+        IEnumerator DelayedInit()
+        {
+            yield return null;
+
+            LayoutSegments();
+
+            if (m_selectedSegmentIndex != -1)
+                selectedSegmentIndex = m_selectedSegmentIndex;
+        }
+
+#if UNITY_EDITOR
+        protected override void OnValidate()
+        {
+            base.OnValidate();
+
+            if (isActiveAndEnabled)
+                StartCoroutine(DelayedInit());
+
+            if (m_selectedSegmentIndex > transform.childCount)
+            {
+                selectedSegmentIndex = transform.childCount - 1;
+            }
+        }
+#endif
+
+        private Selectable[] GetChildSegments()
+        {
+            var buttons = GetComponentsInChildren<Selectable>();
+            if (buttons.Length < 2)
+            {
+                throw new InvalidOperationException("A segmented control must have at least two Button children");
+            }
+
+            for (int i = 0; i < buttons.Length; i++)
+            {
+                var segment = buttons[i].GetComponent<Segment>();
+                if (segment != null)
+                {
+                    segment.index = i;
+                    segment.segmentedControl = this;
+                }
+            }
+
+            return buttons;
+        }
+
+        private void RecreateSprites()
+        {
+            for (int i = 0; i < segments.Length; i++)
+            {
+                if (segments[i].image == null)
+                    continue;
+
+                var sprite = CutSprite(segments[i].image.sprite, i == 0, i == segments.Length - 1);
+                var segment = segments[i].GetComponent<Segment>();
+                if (segment)
+                {
+                    segment.cutSprite = sprite;
+                }
+                segments[i].image.overrideSprite = sprite;
+            }
+        }
+
+        static internal Sprite CutSprite(Sprite sprite, bool leftmost, bool rightmost)
+        {
+            if (sprite.border.x == 0 || sprite.border.z == 0)
+                return sprite;
+
+            var rect = sprite.rect;
+            var border = sprite.border;
+
+            if (!leftmost)
+            {
+                rect.xMin = border.x;
+                border.x = 0;
+            }
+            if (!rightmost)
+            {
+                rect.xMax = border.z;
+                border.z = 0;
+            }
+
+            return Sprite.Create(sprite.texture, rect, sprite.pivot, sprite.pixelsPerUnit, 0, SpriteMeshType.FullRect, border);
+        }
+
+        public void LayoutSegments()
+        {
+            RecreateSprites();
+
+            RectTransform transform = this.transform as RectTransform;
+            float width = (transform.rect.width / segments.Length) - (SeparatorWidth * (segments.Length - 1));
+
+            for (int i = 0; i < segments.Length; i++)
+            {
+                float insetX = ((width + SeparatorWidth) * i);
+
+                var rectTransform = segments[i].GetComponent<RectTransform>();
+                rectTransform.anchorMin = Vector2.zero;
+                rectTransform.anchorMax = Vector2.zero;
+                rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, insetX, width);
+                rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, transform.rect.height);
+
+                if (separator && i > 0)
+                {
+                    var sepTransform = gameObject.transform.Find("Separator " + i);
+                    Graphic sep = (sepTransform != null) ? sepTransform.GetComponent<Graphic>() : (GameObject.Instantiate(separator.gameObject) as GameObject).GetComponent<Graphic>();
+                    sep.gameObject.name = "Separator " + i;
+                    sep.gameObject.SetActive(true);
+                    sep.rectTransform.SetParent(this.transform, false);
+                    sep.rectTransform.anchorMin = Vector2.zero;
+                    sep.rectTransform.anchorMax = Vector2.zero;
+                    sep.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, insetX - SeparatorWidth, SeparatorWidth);
+                    sep.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, transform.rect.height);
+                }
+// TODO: maybe adjust text position
+            }
+        }
+    }
+}

Some files were not shown because too many files changed in this diff