DropdownMenuBuilder.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. package me.shedaniel.clothconfig2.impl.builders;
  2. import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry;
  3. import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry.DefaultSelectionCellCreator;
  4. import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry.DefaultSelectionTopCellElement;
  5. import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry.SelectionCellCreator;
  6. import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry.SelectionTopCellElement;
  7. import net.fabricmc.api.EnvType;
  8. import net.fabricmc.api.Environment;
  9. import net.minecraft.block.Block;
  10. import net.minecraft.client.MinecraftClient;
  11. import net.minecraft.client.render.item.ItemRenderer;
  12. import net.minecraft.client.util.math.MatrixStack;
  13. import net.minecraft.item.Item;
  14. import net.minecraft.item.ItemStack;
  15. import net.minecraft.item.Items;
  16. import net.minecraft.text.LiteralText;
  17. import net.minecraft.text.Text;
  18. import net.minecraft.util.Identifier;
  19. import net.minecraft.util.registry.Registry;
  20. import org.jetbrains.annotations.NotNull;
  21. import java.util.Collections;
  22. import java.util.Objects;
  23. import java.util.Optional;
  24. import java.util.function.Consumer;
  25. import java.util.function.Function;
  26. import java.util.function.Supplier;
  27. @Environment(EnvType.CLIENT)
  28. public class DropdownMenuBuilder<T> extends FieldBuilder<T, DropdownBoxEntry<T>> {
  29. protected SelectionTopCellElement<T> topCellElement;
  30. protected SelectionCellCreator<T> cellCreator;
  31. protected Function<T, Optional<Text[]>> tooltipSupplier = str -> Optional.empty();
  32. protected Consumer<T> saveConsumer = null;
  33. protected Iterable<T> selections = Collections.emptyList();
  34. protected boolean suggestionMode = true;
  35. public DropdownMenuBuilder(Text resetButtonKey, Text fieldNameKey, SelectionTopCellElement<T> topCellElement, SelectionCellCreator<T> cellCreator) {
  36. super(resetButtonKey, fieldNameKey);
  37. this.topCellElement = Objects.requireNonNull(topCellElement);
  38. this.cellCreator = Objects.requireNonNull(cellCreator);
  39. }
  40. public DropdownMenuBuilder<T> setSelections(Iterable<T> selections) {
  41. this.selections = selections;
  42. return this;
  43. }
  44. public DropdownMenuBuilder<T> setDefaultValue(Supplier<T> defaultValue) {
  45. this.defaultValue = defaultValue;
  46. return this;
  47. }
  48. public DropdownMenuBuilder<T> setDefaultValue(T defaultValue) {
  49. this.defaultValue = () -> Objects.requireNonNull(defaultValue);
  50. return this;
  51. }
  52. public DropdownMenuBuilder<T> setSaveConsumer(Consumer<T> saveConsumer) {
  53. this.saveConsumer = saveConsumer;
  54. return this;
  55. }
  56. public DropdownMenuBuilder<T> setTooltipSupplier(Supplier<Optional<Text[]>> tooltipSupplier) {
  57. this.tooltipSupplier = str -> tooltipSupplier.get();
  58. return this;
  59. }
  60. public DropdownMenuBuilder<T> setTooltipSupplier(Function<T, Optional<Text[]>> tooltipSupplier) {
  61. this.tooltipSupplier = tooltipSupplier;
  62. return this;
  63. }
  64. public DropdownMenuBuilder<T> setTooltip(Optional<Text[]> tooltip) {
  65. this.tooltipSupplier = str -> tooltip;
  66. return this;
  67. }
  68. public DropdownMenuBuilder<T> setTooltip(Text... tooltip) {
  69. this.tooltipSupplier = str -> Optional.ofNullable(tooltip);
  70. return this;
  71. }
  72. public DropdownMenuBuilder<T> requireRestart() {
  73. requireRestart(true);
  74. return this;
  75. }
  76. public DropdownMenuBuilder<T> setErrorSupplier(Function<T, Optional<Text>> errorSupplier) {
  77. this.errorSupplier = errorSupplier;
  78. return this;
  79. }
  80. public DropdownMenuBuilder<T> setSuggestionMode(boolean suggestionMode) {
  81. this.suggestionMode = suggestionMode;
  82. return this;
  83. }
  84. public boolean isSuggestionMode() {
  85. return suggestionMode;
  86. }
  87. @NotNull
  88. @Override
  89. public DropdownBoxEntry<T> build() {
  90. DropdownBoxEntry<T> entry = new DropdownBoxEntry<>(getFieldNameKey(), getResetButtonKey(), null, isRequireRestart(), defaultValue, saveConsumer, selections, topCellElement, cellCreator);
  91. entry.setTooltipSupplier(() -> tooltipSupplier.apply(entry.getValue()));
  92. if (errorSupplier != null)
  93. entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue()));
  94. entry.setSuggestionMode(suggestionMode);
  95. return entry;
  96. }
  97. public static class TopCellElementBuilder {
  98. public static final Function<String, Identifier> IDENTIFIER_FUNCTION = str -> {
  99. try {
  100. return new Identifier(str);
  101. } catch (NumberFormatException e) {
  102. return null;
  103. }
  104. };
  105. public static final Function<String, Identifier> ITEM_IDENTIFIER_FUNCTION = str -> {
  106. try {
  107. Identifier identifier = new Identifier(str);
  108. if (Registry.ITEM.getOrEmpty(identifier).isPresent())
  109. return identifier;
  110. } catch (Exception ignored) {
  111. }
  112. return null;
  113. };
  114. public static final Function<String, Identifier> BLOCK_IDENTIFIER_FUNCTION = str -> {
  115. try {
  116. Identifier identifier = new Identifier(str);
  117. if (Registry.BLOCK.getOrEmpty(identifier).isPresent())
  118. return identifier;
  119. } catch (Exception ignored) {
  120. }
  121. return null;
  122. };
  123. public static final Function<String, Item> ITEM_FUNCTION = str -> {
  124. try {
  125. return Registry.ITEM.getOrEmpty(new Identifier(str)).orElse(null);
  126. } catch (Exception ignored) {
  127. }
  128. return null;
  129. };
  130. public static final Function<String, Block> BLOCK_FUNCTION = str -> {
  131. try {
  132. return Registry.BLOCK.getOrEmpty(new Identifier(str)).orElse(null);
  133. } catch (Exception ignored) {
  134. }
  135. return null;
  136. };
  137. private static final ItemStack BARRIER = new ItemStack(Items.BARRIER);
  138. public static <T> SelectionTopCellElement<T> of(T value, Function<String, T> toObjectFunction) {
  139. return of(value, toObjectFunction, t -> new LiteralText(t.toString()));
  140. }
  141. public static <T> SelectionTopCellElement<T> of(T value, Function<String, T> toObjectFunction, Function<T, Text> toTextFunction) {
  142. return new DefaultSelectionTopCellElement<>(value, toObjectFunction, toTextFunction);
  143. }
  144. public static SelectionTopCellElement<Identifier> ofItemIdentifier(Item item) {
  145. return new DefaultSelectionTopCellElement<Identifier>(Registry.ITEM.getId(item), ITEM_IDENTIFIER_FUNCTION, identifier -> new LiteralText(identifier.toString())) {
  146. @Override
  147. public void render(MatrixStack matrices, int mouseX, int mouseY, int x, int y, int width, int height, float delta) {
  148. textFieldWidget.x = x + 4;
  149. textFieldWidget.y = y + 6;
  150. textFieldWidget.setWidth(width - 4 - 20);
  151. textFieldWidget.setEditable(getParent().isEditable());
  152. textFieldWidget.setEditableColor(getPreferredTextColor());
  153. textFieldWidget.render(matrices, mouseX, mouseY, delta);
  154. ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
  155. ItemStack stack = hasConfigError() ? BARRIER : new ItemStack(Registry.ITEM.get(getValue()));
  156. itemRenderer.renderGuiItemIcon(stack, x + width - 18, y + 2);
  157. }
  158. };
  159. }
  160. public static SelectionTopCellElement<Identifier> ofBlockIdentifier(Block block) {
  161. return new DefaultSelectionTopCellElement<Identifier>(Registry.BLOCK.getId(block), BLOCK_IDENTIFIER_FUNCTION, identifier -> new LiteralText(identifier.toString())) {
  162. @Override
  163. public void render(MatrixStack matrices, int mouseX, int mouseY, int x, int y, int width, int height, float delta) {
  164. textFieldWidget.x = x + 4;
  165. textFieldWidget.y = y + 6;
  166. textFieldWidget.setWidth(width - 4 - 20);
  167. textFieldWidget.setEditable(getParent().isEditable());
  168. textFieldWidget.setEditableColor(getPreferredTextColor());
  169. textFieldWidget.render(matrices, mouseX, mouseY, delta);
  170. ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
  171. ItemStack stack = hasConfigError() ? BARRIER : new ItemStack(Registry.BLOCK.get(getValue()));
  172. itemRenderer.renderGuiItemIcon(stack, x + width - 18, y + 2);
  173. }
  174. };
  175. }
  176. public static SelectionTopCellElement<Item> ofItemObject(Item item) {
  177. return new DefaultSelectionTopCellElement<Item>(item, ITEM_FUNCTION, i -> new LiteralText(Registry.ITEM.getId(i).toString())) {
  178. @Override
  179. public void render(MatrixStack matrices, int mouseX, int mouseY, int x, int y, int width, int height, float delta) {
  180. textFieldWidget.x = x + 4;
  181. textFieldWidget.y = y + 6;
  182. textFieldWidget.setWidth(width - 4 - 20);
  183. textFieldWidget.setEditable(getParent().isEditable());
  184. textFieldWidget.setEditableColor(getPreferredTextColor());
  185. textFieldWidget.render(matrices, mouseX, mouseY, delta);
  186. ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
  187. ItemStack stack = hasConfigError() ? BARRIER : new ItemStack(getValue());
  188. itemRenderer.renderGuiItemIcon(stack, x + width - 18, y + 2);
  189. }
  190. };
  191. }
  192. public static SelectionTopCellElement<Block> ofBlockObject(Block block) {
  193. return new DefaultSelectionTopCellElement<Block>(block, BLOCK_FUNCTION, i -> new LiteralText(Registry.BLOCK.getId(i).toString())) {
  194. @Override
  195. public void render(MatrixStack matrices, int mouseX, int mouseY, int x, int y, int width, int height, float delta) {
  196. textFieldWidget.x = x + 4;
  197. textFieldWidget.y = y + 6;
  198. textFieldWidget.setWidth(width - 4 - 20);
  199. textFieldWidget.setEditable(getParent().isEditable());
  200. textFieldWidget.setEditableColor(getPreferredTextColor());
  201. textFieldWidget.render(matrices, mouseX, mouseY, delta);
  202. ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
  203. ItemStack stack = hasConfigError() ? BARRIER : new ItemStack(getValue());
  204. itemRenderer.renderGuiItemIcon(stack, x + width - 18, y + 2);
  205. }
  206. };
  207. }
  208. }
  209. public static class CellCreatorBuilder {
  210. public static <T> SelectionCellCreator<T> of() {
  211. return new DefaultSelectionCellCreator<>();
  212. }
  213. public static <T> SelectionCellCreator<T> of(Function<T, Text> toTextFunction) {
  214. return new DefaultSelectionCellCreator<>(toTextFunction);
  215. }
  216. public static <T> SelectionCellCreator<T> ofWidth(int cellWidth) {
  217. return new DefaultSelectionCellCreator<T>() {
  218. @Override
  219. public int getCellWidth() {
  220. return cellWidth;
  221. }
  222. };
  223. }
  224. public static <T> SelectionCellCreator<T> ofWidth(int cellWidth, Function<T, Text> toTextFunction) {
  225. return new DefaultSelectionCellCreator<T>(toTextFunction) {
  226. @Override
  227. public int getCellWidth() {
  228. return cellWidth;
  229. }
  230. };
  231. }
  232. public static <T> SelectionCellCreator<T> ofCellCount(int maxItems) {
  233. return new DefaultSelectionCellCreator<T>() {
  234. @Override
  235. public int getDropBoxMaxHeight() {
  236. return getCellHeight() * maxItems;
  237. }
  238. };
  239. }
  240. public static <T> SelectionCellCreator<T> ofCellCount(int maxItems, Function<T, Text> toTextFunction) {
  241. return new DefaultSelectionCellCreator<T>(toTextFunction) {
  242. @Override
  243. public int getDropBoxMaxHeight() {
  244. return getCellHeight() * maxItems;
  245. }
  246. };
  247. }
  248. public static <T> SelectionCellCreator<T> of(int cellWidth, int maxItems) {
  249. return new DefaultSelectionCellCreator<T>() {
  250. @Override
  251. public int getCellWidth() {
  252. return cellWidth;
  253. }
  254. @Override
  255. public int getDropBoxMaxHeight() {
  256. return getCellHeight() * maxItems;
  257. }
  258. };
  259. }
  260. public static <T> SelectionCellCreator<T> of(int cellWidth, int maxItems, Function<T, Text> toTextFunction) {
  261. return new DefaultSelectionCellCreator<T>(toTextFunction) {
  262. @Override
  263. public int getCellWidth() {
  264. return cellWidth;
  265. }
  266. @Override
  267. public int getDropBoxMaxHeight() {
  268. return getCellHeight() * maxItems;
  269. }
  270. };
  271. }
  272. public static <T> SelectionCellCreator<T> of(int cellHeight, int cellWidth, int maxItems) {
  273. return new DefaultSelectionCellCreator<T>() {
  274. @Override
  275. public int getCellHeight() {
  276. return cellHeight;
  277. }
  278. @Override
  279. public int getCellWidth() {
  280. return cellWidth;
  281. }
  282. @Override
  283. public int getDropBoxMaxHeight() {
  284. return getCellHeight() * maxItems;
  285. }
  286. };
  287. }
  288. public static <T> SelectionCellCreator<T> of(int cellHeight, int cellWidth, int maxItems, Function<T, Text> toTextFunction) {
  289. return new DefaultSelectionCellCreator<T>(toTextFunction) {
  290. @Override
  291. public int getCellHeight() {
  292. return cellHeight;
  293. }
  294. @Override
  295. public int getCellWidth() {
  296. return cellWidth;
  297. }
  298. @Override
  299. public int getDropBoxMaxHeight() {
  300. return getCellHeight() * maxItems;
  301. }
  302. };
  303. }
  304. public static SelectionCellCreator<Identifier> ofItemIdentifier() {
  305. return ofItemIdentifier(20, 146, 7);
  306. }
  307. public static SelectionCellCreator<Identifier> ofItemIdentifier(int maxItems) {
  308. return ofItemIdentifier(20, 146, maxItems);
  309. }
  310. public static SelectionCellCreator<Identifier> ofItemIdentifier(int cellHeight, int cellWidth, int maxItems) {
  311. return new DefaultSelectionCellCreator<Identifier>() {
  312. @Override
  313. public DropdownBoxEntry.SelectionCellElement<Identifier> create(Identifier selection) {
  314. ItemStack s = new ItemStack(Registry.ITEM.get(selection));
  315. return new DropdownBoxEntry.DefaultSelectionCellElement<Identifier>(selection, toTextFunction) {
  316. @Override
  317. public void render(MatrixStack matrices, int mouseX, int mouseY, int x, int y, int width, int height, float delta) {
  318. rendering = true;
  319. this.x = x;
  320. this.y = y;
  321. this.width = width;
  322. this.height = height;
  323. boolean b = mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height;
  324. if (b)
  325. fill(matrices, x + 1, y + 1, x + width - 1, y + height - 1, -15132391);
  326. MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, toTextFunction.apply(r), x + 6 + 18, y + 6, b ? 16777215 : 8947848);
  327. ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
  328. itemRenderer.renderGuiItemIcon(s, x + 4, y + 2);
  329. }
  330. };
  331. }
  332. @Override
  333. public int getCellHeight() {
  334. return cellHeight;
  335. }
  336. @Override
  337. public int getCellWidth() {
  338. return cellWidth;
  339. }
  340. @Override
  341. public int getDropBoxMaxHeight() {
  342. return getCellHeight() * maxItems;
  343. }
  344. };
  345. }
  346. public static SelectionCellCreator<Identifier> ofBlockIdentifier() {
  347. return ofBlockIdentifier(20, 146, 7);
  348. }
  349. public static SelectionCellCreator<Identifier> ofBlockIdentifier(int maxItems) {
  350. return ofBlockIdentifier(20, 146, maxItems);
  351. }
  352. public static SelectionCellCreator<Identifier> ofBlockIdentifier(int cellHeight, int cellWidth, int maxItems) {
  353. return new DefaultSelectionCellCreator<Identifier>() {
  354. @Override
  355. public DropdownBoxEntry.SelectionCellElement<Identifier> create(Identifier selection) {
  356. ItemStack s = new ItemStack(Registry.BLOCK.get(selection));
  357. return new DropdownBoxEntry.DefaultSelectionCellElement<Identifier>(selection, toTextFunction) {
  358. @Override
  359. public void render(MatrixStack matrices, int mouseX, int mouseY, int x, int y, int width, int height, float delta) {
  360. rendering = true;
  361. this.x = x;
  362. this.y = y;
  363. this.width = width;
  364. this.height = height;
  365. boolean b = mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height;
  366. if (b)
  367. fill(matrices, x + 1, y + 1, x + width - 1, y + height - 1, -15132391);
  368. MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, toTextFunction.apply(r), x + 6 + 18, y + 6, b ? 16777215 : 8947848);
  369. ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
  370. itemRenderer.renderGuiItemIcon(s, x + 4, y + 2);
  371. }
  372. };
  373. }
  374. @Override
  375. public int getCellHeight() {
  376. return cellHeight;
  377. }
  378. @Override
  379. public int getCellWidth() {
  380. return cellWidth;
  381. }
  382. @Override
  383. public int getDropBoxMaxHeight() {
  384. return getCellHeight() * maxItems;
  385. }
  386. };
  387. }
  388. public static SelectionCellCreator<Item> ofItemObject() {
  389. return ofItemObject(20, 146, 7);
  390. }
  391. public static SelectionCellCreator<Item> ofItemObject(int maxItems) {
  392. return ofItemObject(20, 146, maxItems);
  393. }
  394. public static SelectionCellCreator<Item> ofItemObject(int cellHeight, int cellWidth, int maxItems) {
  395. return new DefaultSelectionCellCreator<Item>(i -> new LiteralText(Registry.ITEM.getId(i).toString())) {
  396. @Override
  397. public DropdownBoxEntry.SelectionCellElement<Item> create(Item selection) {
  398. ItemStack s = new ItemStack(selection);
  399. return new DropdownBoxEntry.DefaultSelectionCellElement<Item>(selection, toTextFunction) {
  400. @Override
  401. public void render(MatrixStack matrices, int mouseX, int mouseY, int x, int y, int width, int height, float delta) {
  402. rendering = true;
  403. this.x = x;
  404. this.y = y;
  405. this.width = width;
  406. this.height = height;
  407. boolean b = mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height;
  408. if (b)
  409. fill(matrices, x + 1, y + 1, x + width - 1, y + height - 1, -15132391);
  410. MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, toTextFunction.apply(r), x + 6 + 18, y + 6, b ? 16777215 : 8947848);
  411. ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
  412. itemRenderer.renderGuiItemIcon(s, x + 4, y + 2);
  413. }
  414. };
  415. }
  416. @Override
  417. public int getCellHeight() {
  418. return cellHeight;
  419. }
  420. @Override
  421. public int getCellWidth() {
  422. return cellWidth;
  423. }
  424. @Override
  425. public int getDropBoxMaxHeight() {
  426. return getCellHeight() * maxItems;
  427. }
  428. };
  429. }
  430. public static SelectionCellCreator<Block> ofBlockObject() {
  431. return ofBlockObject(20, 146, 7);
  432. }
  433. public static SelectionCellCreator<Block> ofBlockObject(int maxItems) {
  434. return ofBlockObject(20, 146, maxItems);
  435. }
  436. public static SelectionCellCreator<Block> ofBlockObject(int cellHeight, int cellWidth, int maxItems) {
  437. return new DefaultSelectionCellCreator<Block>(i -> new LiteralText(Registry.BLOCK.getId(i).toString())) {
  438. @Override
  439. public DropdownBoxEntry.SelectionCellElement<Block> create(Block selection) {
  440. ItemStack s = new ItemStack(selection);
  441. return new DropdownBoxEntry.DefaultSelectionCellElement<Block>(selection, toTextFunction) {
  442. @Override
  443. public void render(MatrixStack matrices, int mouseX, int mouseY, int x, int y, int width, int height, float delta) {
  444. rendering = true;
  445. this.x = x;
  446. this.y = y;
  447. this.width = width;
  448. this.height = height;
  449. boolean b = mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height;
  450. if (b)
  451. fill(matrices, x + 1, y + 1, x + width - 1, y + height - 1, -15132391);
  452. MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, toTextFunction.apply(r), x + 6 + 18, y + 6, b ? 16777215 : 8947848);
  453. ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
  454. itemRenderer.renderGuiItemIcon(s, x + 4, y + 2);
  455. }
  456. };
  457. }
  458. @Override
  459. public int getCellHeight() {
  460. return cellHeight;
  461. }
  462. @Override
  463. public int getCellWidth() {
  464. return cellWidth;
  465. }
  466. @Override
  467. public int getDropBoxMaxHeight() {
  468. return getCellHeight() * maxItems;
  469. }
  470. };
  471. }
  472. }
  473. }