From 759b49e9e02a9e7101dfde6a77bb5ac5e31009e0 Mon Sep 17 00:00:00 2001 From: Patrick <147879351+WinniePatGG@users.noreply.github.com> Date: Sat, 20 Jun 2026 21:45:01 +0200 Subject: [PATCH] Test Settings Menu --- build.gradle | 6 +- gradle.properties | 3 +- .../parrotmod/mixin/TitleScreenMixin.java | 26 ++--- .../parrotmod/ui/GeneralTabFragment.java | 71 +++++++++++++ .../parrotmod/ui/SettingsFragment.java | 97 ++++++++++++++++++ .../parrotmod/ui/SettingsScreen.java | 35 ------- src/main/resources/assets/parrotmod/icon.png | Bin 3964 -> 0 bytes src/main/resources/fabric.mod.json | 2 +- 8 files changed, 187 insertions(+), 53 deletions(-) create mode 100644 src/main/java/de/winniepat/parrotmod/ui/GeneralTabFragment.java create mode 100644 src/main/java/de/winniepat/parrotmod/ui/SettingsFragment.java delete mode 100644 src/main/java/de/winniepat/parrotmod/ui/SettingsScreen.java delete mode 100644 src/main/resources/assets/parrotmod/icon.png diff --git a/build.gradle b/build.gradle index f0cc49d..aa67876 100644 --- a/build.gradle +++ b/build.gradle @@ -24,9 +24,9 @@ dependencies { implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - implementation "curse.maven:modern-ui-352491:8206272" - implementation "icyllis.modernui:ModernUI-Fabric:26.1.2-3.13.0.4" - implementation "icyllis.arc3d:arc3d-core:2026.1.0" + implementation "dev.icyllis:modernui-core:${modernui_version}" + implementation "icyllis.modernui:ModernUI-Markflow:${modernui_version}" + implementation("icyllis.modernui:ModernUI-Fabric:${minecraft_version}-${modernui_version}.+") } processResources { diff --git a/gradle.properties b/gradle.properties index 217cde9..1927367 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,4 +11,5 @@ maven_group=de.winniepat archives_base_name=ParrotMod # Dependencies # check this on https://modmuss50.me/fabric.html -fabric_version=0.151.0+26.1.2 \ No newline at end of file +fabric_version=0.151.0+26.1.2 +modernui_version=3.13.0 \ No newline at end of file diff --git a/src/main/java/de/winniepat/parrotmod/mixin/TitleScreenMixin.java b/src/main/java/de/winniepat/parrotmod/mixin/TitleScreenMixin.java index 8653cb9..47ef8f6 100644 --- a/src/main/java/de/winniepat/parrotmod/mixin/TitleScreenMixin.java +++ b/src/main/java/de/winniepat/parrotmod/mixin/TitleScreenMixin.java @@ -1,30 +1,30 @@ package de.winniepat.parrotmod.mixin; -import de.winniepat.parrotmod.ui.SettingsScreen; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.Button; // Updated import +import de.winniepat.parrotmod.ui.SettingsFragment; +import icyllis.modernui.mc.MuiModApi; +import net.minecraft.client.gui.components.ImageButton; +import net.minecraft.client.gui.components.WidgetSprites; +import net.minecraft.resources.Identifier; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.TitleScreen; -import net.minecraft.network.chat.Component; // Replaces Text +import net.minecraft.network.chat.Component; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(TitleScreen.class) -public class TitleScreenMixin extends Screen { +public abstract class TitleScreenMixin extends Screen { protected TitleScreenMixin(Component title) { super(title); } - @Inject(at = @At("RETURN"), method = "init") - private void addCustomButton(CallbackInfo ci) { - int x = this.width / 2 - 100; - int y = this.height / 4 + 120; - - this.addRenderableWidget(Button.builder(Component.literal("Parrot Mod"), (button) -> { - Minecraft.getInstance().setScreen(new SettingsScreen(Component.literal("Settings"))); - }).bounds(x, y, 200, 20).build()); + @Inject(method = "init", at = @At("TAIL")) + private void onInit(CallbackInfo ci) { + WidgetSprites sprites = new WidgetSprites(Identifier.fromNamespaceAndPath("parrotmod", "icon"), Identifier.fromNamespaceAndPath("parrotmod", "icon")); + this.addRenderableWidget(new ImageButton(this.width / 2 + 104, this.height / 4 + 48, 20, 20, sprites, b -> { + MuiModApi.get().openScreen(new SettingsFragment()); + })); } } \ No newline at end of file diff --git a/src/main/java/de/winniepat/parrotmod/ui/GeneralTabFragment.java b/src/main/java/de/winniepat/parrotmod/ui/GeneralTabFragment.java new file mode 100644 index 0000000..7ebd746 --- /dev/null +++ b/src/main/java/de/winniepat/parrotmod/ui/GeneralTabFragment.java @@ -0,0 +1,71 @@ +package de.winniepat.parrotmod.ui; + +import icyllis.modernui.fragment.Fragment; +import icyllis.modernui.util.DataSet; +import icyllis.modernui.view.*; +import icyllis.modernui.widget.*; + +public class GeneralTabFragment extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, DataSet savedInstanceState) { + LinearLayout layout = new LinearLayout(getContext()); + layout.setOrientation(LinearLayout.VERTICAL); + layout.setPadding(dp(12), dp(12), dp(12), dp(12)); + + // --- A toggle/switch setting --- + layout.addView(makeLabel("Enable feature X")); + Switch toggleX = new Switch(getContext()); + toggleX.setChecked(true); // load from your config + toggleX.setOnCheckedChangeListener((v, checked) -> { + // save to config + MyConfig.enableFeatureX = checked; + }); + layout.addView(toggleX, rowParams()); + + // --- Another toggle --- + layout.addView(makeLabel("Show HUD overlay")); + Switch toggleHUD = new Switch(getContext()); + toggleHUD.setChecked(MyConfig.showHud); + toggleHUD.setOnCheckedChangeListener((v, checked) -> MyConfig.showHud = checked); + layout.addView(toggleHUD, rowParams()); + + // --- A slider --- + layout.addView(makeLabel("Opacity")); + SeekBar slider = new SeekBar(getContext()); + slider.setMax(100); + slider.setProgress((int)(MyConfig.opacity * 100)); + slider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + public void onProgressChanged(SeekBar bar, int progress, boolean fromUser) { + if (fromUser) MyConfig.opacity = progress / 100f; + } + public void onStartTrackingTouch(SeekBar bar) {} + public void onStopTrackingTouch(SeekBar bar) {} + }); + layout.addView(slider, rowParams()); + + return layout; + } + + private TextView makeLabel(String text) { + TextView tv = new TextView(getContext()); + tv.setText(text); + tv.setTextSize(12); + tv.setTextColor(0xFFCCCCCC); + var p = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + p.topMargin = dp(8); + p.bottomMargin = dp(2); + tv.setLayoutParams(p); + return tv; + } + + private LinearLayout.LayoutParams rowParams() { + return new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, dp(28)); + } + + private int dp(float dp) { + return (int) (dp * getContext().getResources().getDisplayMetrics().density); + } +} \ No newline at end of file diff --git a/src/main/java/de/winniepat/parrotmod/ui/SettingsFragment.java b/src/main/java/de/winniepat/parrotmod/ui/SettingsFragment.java new file mode 100644 index 0000000..8918079 --- /dev/null +++ b/src/main/java/de/winniepat/parrotmod/ui/SettingsFragment.java @@ -0,0 +1,97 @@ +package de.winniepat.parrotmod.ui; + +import icyllis.modernui.R; +import icyllis.modernui.fragment.Fragment; +import icyllis.modernui.util.DataSet; +import icyllis.modernui.view.*; +import icyllis.modernui.widget.*; +import icyllis.modernui.graphics.drawable.ShapeDrawable; +import icyllis.modernui.graphics.*; + +public class SettingsFragment extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, DataSet savedInstanceState) { + LinearLayout root = new LinearLayout(getContext()); + root.setOrientation(LinearLayout.HORIZONTAL); + root.setLayoutParams(new FrameLayout.LayoutParams( + dp(520), dp(320), Gravity.CENTER)); + + // --- LEFT PANEL: tab buttons stacked vertically --- + LinearLayout sidebar = new LinearLayout(getContext()); + sidebar.setOrientation(LinearLayout.VERTICAL); + sidebar.setPadding(dp(8), dp(8), dp(8), dp(8)); + // Semi-transparent dark background + sidebar.setBackground(makeRoundedBg(0xCC1A1A2E)); + + var sidebarParams = new LinearLayout.LayoutParams(dp(110), ViewGroup.LayoutParams.MATCH_PARENT); + root.addView(sidebar, sidebarParams); + + // --- RIGHT PANEL: fragment host --- + FrameLayout contentArea = new FrameLayout(getContext()); + contentArea.setId(R.id.content); // or any stable int ID, e.g. 0x10001 + contentArea.setBackground(makeRoundedBg(0xCC101018)); + + var contentParams = new LinearLayout.LayoutParams( + 0, ViewGroup.LayoutParams.MATCH_PARENT, 1f); // weight=1, fills remaining space + contentParams.leftMargin = dp(6); + root.addView(contentArea, contentParams); + + String[] tabNames = {"General", "Graphics", "Audio", "Keybinds"}; + Fragment[] tabFragments = { + new GeneralTabFragment() + }; + + // Show the first tab immediately + getChildFragmentManager().beginTransaction() + .replace(contentArea.getId(), tabFragments[0]) + .commitNow(); + + Button[] tabs = new Button[tabNames.length]; + for (int i = 0; i < tabNames.length; i++) { + final int index = i; + Button tab = new Button(getContext()); + tab.setText(tabNames[i]); + tab.setTextSize(13); + tab.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); + tab.setPadding(dp(10), dp(6), dp(10), dp(6)); + tab.setBackground(null); // we'll tint active tab manually + + tab.setOnClickListener(v -> { + // Swap content fragment + getChildFragmentManager().beginTransaction() + .setReorderingAllowed(true) + .replace(contentArea.getId(), tabFragments[index]) + .commit(); + // Highlight active tab + for (Button b : tabs) b.setTextColor(0xFFAAAAAA); + tab.setTextColor(0xFFFFFFFF); + }); + + var tabParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, dp(32)); + tabParams.bottomMargin = dp(4); + sidebar.addView(tab, tabParams); + tabs[i] = tab; + } + + // Default: highlight first tab + tabs[0].setTextColor(0xFFFFFFFF); + for (int i = 1; i < tabs.length; i++) tabs[i].setTextColor(0xFFAAAAAA); + + return root; + } + + // Helper: dp → px + private int dp(float dp) { + return (int) (dp * getContext().getResources().getDisplayMetrics().density); + } + + // Helper: semi-transparent rounded rectangle background + private ShapeDrawable makeRoundedBg(int color) { + ShapeDrawable d = new ShapeDrawable(); + d.setCornerRadius(dp(6)); + d.setColor(color); + return d; + } +} \ No newline at end of file diff --git a/src/main/java/de/winniepat/parrotmod/ui/SettingsScreen.java b/src/main/java/de/winniepat/parrotmod/ui/SettingsScreen.java deleted file mode 100644 index 81bc147..0000000 --- a/src/main/java/de/winniepat/parrotmod/ui/SettingsScreen.java +++ /dev/null @@ -1,35 +0,0 @@ -package de.winniepat.parrotmod.ui; - -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.Renderable; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; - -public class SettingsScreen extends Screen { - private int tabWidth = 100; - private int currentTab = 0; - - public SettingsScreen(Component title) { - super(title); - } - - @Override - protected void init() { - this.addRenderableWidget(Button.builder(Component.literal("General"), (b) -> { - this.currentTab = 0; - this.rebuildWidgets();; - }).bounds(10, 65, tabWidth, 20).build()); - - this.addRenderableWidget(Button.builder(Component.literal("Graphics"), (b) -> { - this.currentTab = 1; - this.rebuildWidgets(); - }).bounds(10, 65, tabWidth, 20).build()); - - if (currentTab == 0) { - this.addRenderableWidget(Button.builder(Component.literal("Enable Mod"), (b) -> { - System.out.println("Enable Mod clicked"); - }).bounds(tabWidth + 30, 40, 150, 20).build()); - } - } - -} diff --git a/src/main/resources/assets/parrotmod/icon.png b/src/main/resources/assets/parrotmod/icon.png deleted file mode 100644 index a4c15f39ccf83ad32a28719e9ed2d4a5606bb1dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3964 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