1
0

SingleMarkingPicker.xaml.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. using System.Linq;
  2. using Content.Shared.Humanoid.Markings;
  3. using Robust.Client.AutoGenerated;
  4. using Robust.Client.UserInterface.Controls;
  5. using Robust.Client.UserInterface.XAML;
  6. using Robust.Client.Utility;
  7. namespace Content.Client.Humanoid;
  8. [GenerateTypedNameReferences]
  9. public sealed partial class SingleMarkingPicker : BoxContainer
  10. {
  11. [Dependency] private readonly MarkingManager _markingManager = default!;
  12. /// <summary>
  13. /// What happens if a marking is selected.
  14. /// It will send the 'slot' (marking index)
  15. /// and the selected marking's ID.
  16. /// </summary>
  17. public Action<(int slot, string id)>? OnMarkingSelect;
  18. /// <summary>
  19. /// What happens if a slot is removed.
  20. /// This will send the 'slot' (marking index).
  21. /// </summary>
  22. public Action<int>? OnSlotRemove;
  23. /// <summary>
  24. /// What happens when a slot is added.
  25. /// </summary>
  26. public Action? OnSlotAdd;
  27. /// <summary>
  28. /// What happens if a marking's color is changed.
  29. /// Sends a 'slot' number, and the marking in question.
  30. /// </summary>
  31. public Action<(int slot, Marking marking)>? OnColorChanged;
  32. // current selected slot
  33. private int _slot = -1;
  34. private int Slot
  35. {
  36. get
  37. {
  38. if (_markings == null || _markings.Count == 0)
  39. {
  40. _slot = -1;
  41. }
  42. else if (_slot == -1)
  43. {
  44. _slot = 0;
  45. }
  46. return _slot;
  47. }
  48. set
  49. {
  50. if (_markings == null || _markings.Count == 0)
  51. {
  52. _slot = -1;
  53. return;
  54. }
  55. _slot = value;
  56. _ignoreItemSelected = true;
  57. foreach (var item in MarkingList)
  58. {
  59. item.Selected = (string) item.Metadata! == _markings[_slot].MarkingId;
  60. }
  61. _ignoreItemSelected = false;
  62. PopulateColors();
  63. }
  64. }
  65. // amount of slots to show
  66. private int _totalPoints;
  67. private bool _ignoreItemSelected;
  68. private MarkingCategories _category;
  69. public MarkingCategories Category
  70. {
  71. get => _category;
  72. set
  73. {
  74. _category = value;
  75. CategoryName.Text = Loc.GetString($"markings-category-{_category}");
  76. if (!string.IsNullOrEmpty(_species))
  77. {
  78. PopulateList(Search.Text);
  79. }
  80. }
  81. }
  82. private IReadOnlyDictionary<string, MarkingPrototype>? _markingPrototypeCache;
  83. private string? _species;
  84. private List<Marking>? _markings;
  85. private int PointsLeft
  86. {
  87. get
  88. {
  89. if (_markings == null)
  90. {
  91. return 0;
  92. }
  93. if (_totalPoints < 0)
  94. {
  95. return -1;
  96. }
  97. return _totalPoints - _markings.Count;
  98. }
  99. }
  100. private int PointsUsed => _markings?.Count ?? 0;
  101. public SingleMarkingPicker()
  102. {
  103. RobustXamlLoader.Load(this);
  104. IoCManager.InjectDependencies(this);
  105. MarkingList.OnItemSelected += SelectMarking;
  106. AddButton.OnPressed += _ =>
  107. {
  108. OnSlotAdd!();
  109. };
  110. SlotSelector.OnItemSelected += args =>
  111. {
  112. Slot = args.Button.SelectedId;
  113. };
  114. RemoveButton.OnPressed += _ =>
  115. {
  116. OnSlotRemove!(_slot);
  117. };
  118. Search.OnTextChanged += args =>
  119. {
  120. PopulateList(args.Text);
  121. };
  122. }
  123. public void UpdateData(List<Marking> markings, string species, int totalPoints)
  124. {
  125. _markings = markings;
  126. _species = species;
  127. _totalPoints = totalPoints;
  128. _markingPrototypeCache = _markingManager.MarkingsByCategoryAndSpecies(Category, _species);
  129. Visible = _markingPrototypeCache.Count != 0;
  130. if (_markingPrototypeCache.Count == 0)
  131. {
  132. return;
  133. }
  134. PopulateList(Search.Text);
  135. PopulateColors();
  136. PopulateSlotSelector();
  137. }
  138. public void PopulateList(string filter)
  139. {
  140. if (string.IsNullOrEmpty(_species))
  141. {
  142. throw new ArgumentException("Tried to populate marking list without a set species!");
  143. }
  144. _markingPrototypeCache ??= _markingManager.MarkingsByCategoryAndSpecies(Category, _species);
  145. MarkingSelectorContainer.Visible = _markings != null && _markings.Count != 0;
  146. if (_markings == null || _markings.Count == 0)
  147. {
  148. return;
  149. }
  150. MarkingList.Clear();
  151. var sortedMarkings = _markingPrototypeCache.Where(m =>
  152. m.Key.ToLower().Contains(filter.ToLower()) ||
  153. GetMarkingName(m.Value).ToLower().Contains(filter.ToLower())
  154. ).OrderBy(p => Loc.GetString($"marking-{p.Key}"));
  155. foreach (var (id, marking) in sortedMarkings)
  156. {
  157. var item = MarkingList.AddItem(Loc.GetString($"marking-{id}"), marking.Sprites[0].Frame0());
  158. item.Metadata = marking.ID;
  159. if (_markings[Slot].MarkingId == id)
  160. {
  161. _ignoreItemSelected = true;
  162. item.Selected = true;
  163. _ignoreItemSelected = false;
  164. }
  165. }
  166. }
  167. private void PopulateColors()
  168. {
  169. if (_markings == null
  170. || _markings.Count == 0
  171. || !_markingManager.TryGetMarking(_markings[Slot], out var proto))
  172. {
  173. return;
  174. }
  175. var marking = _markings[Slot];
  176. ColorSelectorContainer.DisposeAllChildren();
  177. ColorSelectorContainer.RemoveAllChildren();
  178. if (marking.MarkingColors.Count != proto.Sprites.Count)
  179. {
  180. marking = new Marking(marking.MarkingId, proto.Sprites.Count);
  181. }
  182. for (var i = 0; i < marking.MarkingColors.Count; i++)
  183. {
  184. var selector = new ColorSelectorSliders
  185. {
  186. HorizontalExpand = true
  187. };
  188. selector.Color = marking.MarkingColors[i];
  189. var colorIndex = i;
  190. selector.OnColorChanged += color =>
  191. {
  192. marking.SetColor(colorIndex, color);
  193. OnColorChanged!((_slot, marking));
  194. };
  195. ColorSelectorContainer.AddChild(selector);
  196. }
  197. }
  198. private void SelectMarking(ItemList.ItemListSelectedEventArgs args)
  199. {
  200. if (_ignoreItemSelected)
  201. {
  202. return;
  203. }
  204. var id = (string) MarkingList[args.ItemIndex].Metadata!;
  205. if (!_markingManager.Markings.TryGetValue(id, out var proto))
  206. {
  207. throw new ArgumentException("Attempted to select non-existent marking.");
  208. }
  209. var oldMarking = _markings![Slot];
  210. _markings[Slot] = proto.AsMarking();
  211. for (var i = 0; i < _markings[Slot].MarkingColors.Count && i < oldMarking.MarkingColors.Count; i++)
  212. {
  213. _markings[Slot].SetColor(i, oldMarking.MarkingColors[i]);
  214. }
  215. PopulateColors();
  216. OnMarkingSelect!((_slot, id));
  217. }
  218. // Slot logic
  219. private void PopulateSlotSelector()
  220. {
  221. SlotSelector.Visible = Slot >= 0;
  222. Search.Visible = Slot >= 0;
  223. AddButton.HorizontalExpand = Slot < 0;
  224. RemoveButton.HorizontalExpand = Slot < 0;
  225. AddButton.Disabled = PointsLeft == 0 && _totalPoints > -1 ;
  226. RemoveButton.Disabled = PointsUsed == 0;
  227. SlotSelector.Clear();
  228. if (Slot < 0)
  229. {
  230. return;
  231. }
  232. for (var i = 0; i < PointsUsed; i++)
  233. {
  234. SlotSelector.AddItem(Loc.GetString("marking-slot", ("number", $"{i + 1}")), i);
  235. if (i == _slot)
  236. {
  237. SlotSelector.SelectId(i);
  238. }
  239. }
  240. }
  241. private string GetMarkingName(MarkingPrototype marking)
  242. {
  243. return Loc.GetString($"marking-{marking.ID}");
  244. }
  245. }