mirror of
https://github.com/FabricMC/fabric.git
synced 2025-03-22 21:15:23 -04:00
Screen API v1 (#645)
* Implement screen api
* Actually update to 20w27a
* Split render and tick events to before and after
* Rename and update
* A bit of javadoc and profiler name fixes
* Add functional interface annotations, move render and ticking events to actual FabricScreen instance.
* Add after screen resize event
* Implement key and mouse click/press and release events.
* Move keyboard and mouse events to their own pojos
* Init and resize are the same thing. Maybe Screen#init needs a rename
* Add mouse scroll events
* checkstyle
* Refresh event instances after init
* Before init is nessecary to listen to addition/removal of child elements
* Polish up the javadoc and do a rename to the public api interface.
* Mappings updates on testmod
* javadoc formatting again
* Rework screen api design to be more ergonomic.
* Add remove event, some javadoc
* Add allow phase
* Module dependencies
* Fix null ticking when no screen is open
* Refer to GLFW constants in mouse click/release events
* Keyboard event GLFW constant javadoc
* Remove redundant qualifier
* Some docs, degetterifying
* Because global go brr add screen params back around
* Add module lifecycle to FMJ
(cherry picked from commit 8e23c1d877
)
This commit is contained in:
parent
36b77c3e9f
commit
9af2c302f9
23 changed files with 2117 additions and 0 deletions
fabric-screen-api-v1
build.gradle
settings.gradlesrc
main
java/net/fabricmc/fabric
api/client/screen/v1
impl/client/screen
mixin/screen
resources
testmod
java/net/fabricmc/fabric/test/screen
resources
6
fabric-screen-api-v1/build.gradle
Normal file
6
fabric-screen-api-v1/build.gradle
Normal file
|
@ -0,0 +1,6 @@
|
|||
archivesBaseName = "fabric-screen-api-v1"
|
||||
version = getSubprojectVersion(project, "1.0.0")
|
||||
|
||||
moduleDependencies(project, [
|
||||
'fabric-api-base'
|
||||
])
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.screen.v1;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.TickableElement;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.fabricmc.fabric.impl.client.screen.ScreenExtensions;
|
||||
|
||||
/**
|
||||
* Holds events related to {@link Screen}s.
|
||||
*
|
||||
* <p>Some events require a screen instance in order to obtain an event instance.
|
||||
* The events that require a screen instance can be identified by the use of a method passing a screen instance.
|
||||
* All events in {@link ScreenKeyboardEvents} and {@link ScreenMouseEvents} require a screen instance.
|
||||
* This registration model is used since a screen being (re)initialized will reset the screen to it's default state, therefore reverting all changes a mod developer may have applied to a screen.
|
||||
* Furthermore this design was chosen to reduce the amount of wasted iterations of events as a mod developer would only need to register screen events for rendering, ticking, keyboards and mice if needed on a per instance basis.
|
||||
*
|
||||
* <p>The primary entrypoint into a screen is when it is being opened, this is signified by an event {@link ScreenEvents#BEFORE_INIT before} and {@link ScreenEvents#AFTER_INIT after} initialization of the screen.
|
||||
*
|
||||
* @see Screens
|
||||
* @see ScreenKeyboardEvents
|
||||
* @see ScreenMouseEvents
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ScreenEvents {
|
||||
/**
|
||||
* An event that is called before {@link Screen#init(MinecraftClient, int, int) a screen is initialized} to it's default state.
|
||||
* It should be noted some of the methods in {@link Screens} such as a screen's {@link Screens#getTextRenderer(Screen) text renderer} may not be initialized yet, and as such their use is discouraged.
|
||||
*
|
||||
* <!--<p>Typically this event is used to register screen events such as listening to when child elements are added to the screen. ------ Uncomment when child add/remove event is added for elements-->
|
||||
* You can still use {@link ScreenEvents#AFTER_INIT} to register events such as keyboard and mouse events.
|
||||
*
|
||||
* <p>The {@link ScreenExtensions} provided by the {@code info} parameter may be used to register tick, render events, keyboard, mouse, additional and removal of child elements (including buttons).
|
||||
* For example, to register an event on inventory like screens after render, the following code could be used:
|
||||
* <pre>{@code
|
||||
* @Override
|
||||
* public void onInitializeClient() {
|
||||
* ScreenEvents.BEFORE_INIT.register((client, screen, scaledWidth, scaledHeight) -> {
|
||||
* if (screen instanceof AbstractInventoryScreen) {
|
||||
* ScreenEvents.getAfterRenderEvent(screen).register((matrices, mouseX, mouseY, tickDelta) -> {
|
||||
* ...
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>This event indicates a screen has been resized, and therefore is being re-initialized.
|
||||
* This event can also indicate that the previous screen has been changed.
|
||||
* @see ScreenEvents#AFTER_INIT
|
||||
*/
|
||||
public static final Event<BeforeInit> BEFORE_INIT = EventFactory.createArrayBacked(BeforeInit.class, callbacks -> (client, screen, scaledWidth, scaledHeight) -> {
|
||||
for (BeforeInit callback : callbacks) {
|
||||
callback.beforeInit(client, screen, scaledWidth, scaledHeight);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An event that is called after {@link Screen#init(MinecraftClient, int, int) a screen is initialized} to it's default state.
|
||||
*
|
||||
* <p>Typically this event is used to modify a screen after the screen has been initialized.
|
||||
* Modifications such as changing sizes of buttons, removing buttons and adding/removing child elements to the screen can be done safely using this event.
|
||||
*
|
||||
* <p>For example, to add a button to the title screen, the following code could be used:
|
||||
* <pre>{@code
|
||||
* ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> {
|
||||
* if (screen instanceof TitleScreen) {
|
||||
* Screens.getButtons(screen).add(new ButtonWidget(...));
|
||||
* }
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Note that by adding an element to a screen, the element is not automatically {@link net.minecraft.client.gui.screen.TickableElement ticked} or {@link net.minecraft.client.gui.Drawable drawn}.
|
||||
* Unless the element is button, you need to call the specific {@link TickableElement#tick() tick} and {@link net.minecraft.client.gui.Drawable#render(MatrixStack, int, int, float) render} methods in the corresponding screen events.
|
||||
*
|
||||
* <p>This event can also indicate that the previous screen has been closed.
|
||||
* @see ScreenEvents#BEFORE_INIT
|
||||
*/
|
||||
public static final Event<AfterInit> AFTER_INIT = EventFactory.createArrayBacked(AfterInit.class, callbacks -> (client, screen, scaledWidth, scaledHeight) -> {
|
||||
for (AfterInit callback : callbacks) {
|
||||
callback.afterInit(client, screen, scaledWidth, scaledHeight);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An event that is called after {@link Screen#removed()} is called.
|
||||
* This event signifies that the screen is now closed.
|
||||
*
|
||||
* <p>This event is typically used to undo any screen specific state changes such as setting the keyboard to receive {@link net.minecraft.client.Keyboard#setRepeatEvents(boolean) repeat events} or terminate threads spawned by a screen.
|
||||
* This event may precede initialization events {@link ScreenEvents#BEFORE_INIT} but there is no guarantee that event will be called immediately afterwards.
|
||||
*/
|
||||
public static Event<Remove> remove(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getRemoveEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called before a screen is rendered.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<BeforeRender> beforeRender(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getBeforeRenderEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called after a screen is rendered.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AfterRender> afterRender(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAfterRenderEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called before a screen is ticked.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<BeforeTick> beforeTick(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getBeforeTickEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called after a screen is ticked.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AfterTick> afterTick(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAfterTickEvent();
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface BeforeInit {
|
||||
void beforeInit(MinecraftClient client, Screen screen, int scaledWidth, int scaledHeight);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AfterInit {
|
||||
void afterInit(MinecraftClient client, Screen screen, int scaledWidth, int scaledHeight);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface Remove {
|
||||
void onRemove(Screen screen);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface BeforeRender {
|
||||
void beforeRender(Screen screen, MatrixStack matrices, int mouseX, int mouseY, float tickDelta);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AfterRender {
|
||||
void afterRender(Screen screen, MatrixStack matrices, int mouseX, int mouseY, float tickDelta);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface BeforeTick {
|
||||
void beforeTick(Screen screen);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AfterTick {
|
||||
void afterTick(Screen screen);
|
||||
}
|
||||
|
||||
private ScreenEvents() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.screen.v1;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.impl.client.screen.ScreenExtensions;
|
||||
|
||||
/**
|
||||
* Events related to use of the keyboard in a {@link Screen}.
|
||||
*
|
||||
* <p>All of these events work on top of a specific screen instance.
|
||||
* Subscriptions will only last as long as the screen itself, they'll disappear once the screen gets refreshed, closed or replaced.
|
||||
* Use {@link ScreenEvents#BEFORE_INIT} to register the desired events every time it is necessary.
|
||||
*
|
||||
* <p>Events are fired in the following order:
|
||||
* <pre>{@code AllowX -> BeforeX -> AfterX}</pre>
|
||||
* If the result of the Allow event is false, then Before and After are not called.
|
||||
*
|
||||
* @see ScreenEvents
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ScreenKeyboardEvents {
|
||||
/**
|
||||
* An event that checks if a key press should be allowed.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AllowKeyPress> allowKeyPress(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAllowKeyPressEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called before a key press is processed for a screen.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<BeforeKeyPress> beforeKeyPress(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getBeforeKeyPressEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called after a key press is processed for a screen.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AfterKeyPress> afterKeyPress(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAfterKeyPressEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that checks if a pressed key should be allowed to release.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AllowKeyRelease> allowKeyRelease(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAllowKeyReleaseEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called after the release of a key is processed for a screen.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<BeforeKeyRelease> beforeKeyRelease(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getBeforeKeyReleaseEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called after the release a key is processed for a screen.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AfterKeyRelease> afterKeyRelease(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAfterKeyReleaseEvent();
|
||||
}
|
||||
|
||||
private ScreenKeyboardEvents() {
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AllowKeyPress {
|
||||
/**
|
||||
* Checks if a key should be allowed to be pressed.
|
||||
*
|
||||
* @param key the named key code which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}
|
||||
* @param scancode the unique/platform-specific scan code of the keyboard input
|
||||
* @param modifiers a GLFW bitfield describing the modifier keys that are held down
|
||||
* @return whether the key press should be processed
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_KEY_Q
|
||||
* @see <a href="https://www.glfw.org/docs/3.3/group__mods.html">Modifier key flags</a>
|
||||
*/
|
||||
boolean allowKeyPress(Screen screen, int key, int scancode, int modifiers);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface BeforeKeyPress {
|
||||
/**
|
||||
* Called before a key press is handled.
|
||||
*
|
||||
* @param key the named key code which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}
|
||||
* @param scancode the unique/platform-specific scan code of the keyboard input
|
||||
* @param modifiers a GLFW bitfield describing the modifier keys that are held down
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_KEY_Q
|
||||
* @see <a href="https://www.glfw.org/docs/3.3/group__mods.html">Modifier key flags</a>
|
||||
*/
|
||||
void beforeKeyPress(Screen screen, int key, int scancode, int modifiers);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AfterKeyPress {
|
||||
/**
|
||||
* Called after a key press is handled.
|
||||
*
|
||||
* @param key the named key code which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}
|
||||
* @param scancode the unique/platform-specific scan code of the keyboard input
|
||||
* @param modifiers a GLFW bitfield describing the modifier keys that are held down
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_KEY_Q
|
||||
* @see <a href="https://www.glfw.org/docs/3.3/group__mods.html">Modifier key flags</a>
|
||||
*/
|
||||
void afterKeyPress(Screen screen, int key, int scancode, int modifiers);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AllowKeyRelease {
|
||||
/**
|
||||
* Checks if a pressed key should be allowed to be released.
|
||||
*
|
||||
* @param key the named key code which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}
|
||||
* @param scancode the unique/platform-specific scan code of the keyboard input
|
||||
* @param modifiers a GLFW bitfield describing the modifier keys that are held down
|
||||
* @return whether the key press should be released
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_KEY_Q
|
||||
* @see <a href="https://www.glfw.org/docs/3.3/group__mods.html">Modifier key flags</a>
|
||||
*/
|
||||
boolean allowKeyRelease(Screen screen, int key, int scancode, int modifiers);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface BeforeKeyRelease {
|
||||
/**
|
||||
* Called before a pressed key has been released.
|
||||
*
|
||||
* @param key the named key code which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}
|
||||
* @param scancode the unique/platform-specific scan code of the keyboard input
|
||||
* @param modifiers a GLFW bitfield describing the modifier keys that are held down
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_KEY_Q
|
||||
* @see <a href="https://www.glfw.org/docs/3.3/group__mods.html">Modifier key flags</a>
|
||||
*/
|
||||
void beforeKeyRelease(Screen screen, int key, int scancode, int modifiers);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AfterKeyRelease {
|
||||
/**
|
||||
* Called after a pressed key has been released.
|
||||
*
|
||||
* @param key the named key code which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}
|
||||
* @param scancode the unique/platform-specific scan code of the keyboard input
|
||||
* @param modifiers a GLFW bitfield describing the modifier keys that are held down
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_KEY_Q
|
||||
* @see <a href="https://www.glfw.org/docs/3.3/group__mods.html">Modifier key flags</a>
|
||||
*/
|
||||
void afterKeyRelease(Screen screen, int key, int scancode, int modifiers);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.screen.v1;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.impl.client.screen.ScreenExtensions;
|
||||
|
||||
/**
|
||||
* Events related to use of the mouse in a {@link Screen}.
|
||||
*
|
||||
* <p>All of these events work on top of a specific screen instance.
|
||||
* Subscriptions will only last as long as the screen itself, they'll disappear once the screen gets refreshed, closed or replaced.
|
||||
* Use {@link ScreenEvents#BEFORE_INIT} to register the desired events every time it is necessary.
|
||||
*
|
||||
* <p>Events are fired in the following order:
|
||||
* <pre>{@code AllowX -> BeforeX -> AfterX}</pre>
|
||||
* If the result of the Allow event is false, then Before and After are not called.
|
||||
*
|
||||
* @see ScreenEvents
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ScreenMouseEvents {
|
||||
/**
|
||||
* An event that checks if the mouse click should be allowed.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AllowMouseClick> allowMouseClick(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAllowMouseClickEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called before a mouse click is processed for a screen.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<BeforeMouseClick> beforeMouseClick(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getBeforeMouseClickEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called after a mouse click is processed for a screen.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AfterMouseClick> afterMouseClick(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAfterMouseClickEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that checks if the mouse click should be allowed to release in a screen.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AllowMouseRelease> allowMouseRelease(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAllowMouseReleaseEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called before the release of a mouse click is processed for a screen.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<BeforeMouseRelease> beforeMouseRelease(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getBeforeMouseReleaseEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called after the release of a mouse click is processed for a screen.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AfterMouseRelease> afterMouseRelease(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAfterMouseReleaseEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is checks if the mouse should be allowed to scroll in a screen.
|
||||
*
|
||||
* <p>This event tracks amount of vertical and horizontal scroll.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AllowMouseScroll> allowMouseScroll(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAllowMouseScrollEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called after mouse scrolling is processed for a screen.
|
||||
*
|
||||
* <p>This event tracks amount of vertical and horizontal scroll.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<BeforeMouseScroll> beforeMouseScroll(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getBeforeMouseScrollEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that is called after mouse scrolling is processed for a screen.
|
||||
*
|
||||
* <p>This event tracks amount a mouse was scrolled both vertically and horizontally.
|
||||
*
|
||||
* @return the event
|
||||
*/
|
||||
public static Event<AfterMouseScroll> afterMouseScroll(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getAfterMouseScrollEvent();
|
||||
}
|
||||
|
||||
private ScreenMouseEvents() {
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AllowMouseClick {
|
||||
/**
|
||||
* @param mouseX the x position of the mouse
|
||||
* @param mouseY the y position of the mouse
|
||||
* @param button the button number, which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}.
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_MOUSE_BUTTON_1
|
||||
*/
|
||||
boolean allowMouseClick(Screen screen, double mouseX, double mouseY, int button);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface BeforeMouseClick {
|
||||
/**
|
||||
* @param mouseX the x position of the mouse
|
||||
* @param mouseY the y position of the mouse
|
||||
* @param button the button number, which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}.
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_MOUSE_BUTTON_1
|
||||
*/
|
||||
void beforeMouseClick(Screen screen, double mouseX, double mouseY, int button);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AfterMouseClick {
|
||||
/**
|
||||
* @param mouseX the x position of the mouse
|
||||
* @param mouseY the y position of the mouse
|
||||
* @param button the button number, which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}.
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_MOUSE_BUTTON_1
|
||||
*/
|
||||
void afterMouseClick(Screen screen, double mouseX, double mouseY, int button);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AllowMouseRelease {
|
||||
/**
|
||||
* Checks if the mouse click should be allowed to release in a screen.
|
||||
*
|
||||
* @param mouseX the x position of the mouse
|
||||
* @param mouseY the y position of the mouse
|
||||
* @param button the button number, which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}.
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_MOUSE_BUTTON_1
|
||||
*/
|
||||
boolean allowMouseRelease(Screen screen, double mouseX, double mouseY, int button);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface BeforeMouseRelease {
|
||||
/**
|
||||
* Called before a mouse click has released in a screen.
|
||||
*
|
||||
* @param mouseX the x position of the mouse
|
||||
* @param mouseY the y position of the mouse
|
||||
* @param button the button number, which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}.
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_MOUSE_BUTTON_1
|
||||
*/
|
||||
void beforeMouseRelease(Screen screen, double mouseX, double mouseY, int button);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AfterMouseRelease {
|
||||
/**
|
||||
* Called after a mouse click has released in a screen.
|
||||
*
|
||||
* @param mouseX the x position of the mouse
|
||||
* @param mouseY the y position of the mouse
|
||||
* @param button the button number, which can be identified by the constants in {@link org.lwjgl.glfw.GLFW GLFW}.
|
||||
* @see org.lwjgl.glfw.GLFW#GLFW_MOUSE_BUTTON_1
|
||||
*/
|
||||
void afterMouseRelease(Screen screen, double mouseX, double mouseY, int button);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AllowMouseScroll {
|
||||
/**
|
||||
* Checks if the mouse should be allowed to scroll in a screen.
|
||||
*
|
||||
* @param mouseX the x position of the mouse
|
||||
* @param mouseY the y position of the mouse
|
||||
* @param horizontalAmount the horizontal scroll amount
|
||||
* @param verticalAmount the vertical scroll amount
|
||||
* @return whether the mouse should be allowed to scroll
|
||||
*/
|
||||
boolean allowMouseScroll(Screen screen, double mouseX, double mouseY, double horizontalAmount, double verticalAmount);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface BeforeMouseScroll {
|
||||
/**
|
||||
* Called before a mouse has scrolled on screen.
|
||||
*
|
||||
* @param mouseX the x position of the mouse
|
||||
* @param mouseY the y position of the mouse
|
||||
* @param horizontalAmount the horizontal scroll amount
|
||||
* @param verticalAmount the vertical scroll amount
|
||||
*/
|
||||
void beforeMouseScroll(Screen screen, double mouseX, double mouseY, double horizontalAmount, double verticalAmount);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@FunctionalInterface
|
||||
public interface AfterMouseScroll {
|
||||
/**
|
||||
* Called after a mouse has scrolled on screen.
|
||||
*
|
||||
* @param mouseX the x position of the mouse
|
||||
* @param mouseY the y position of the mouse
|
||||
* @param horizontalAmount the horizontal scroll amount
|
||||
* @param verticalAmount the vertical scroll amount
|
||||
*/
|
||||
void afterMouseScroll(Screen screen, double mouseX, double mouseY, double horizontalAmount, double verticalAmount);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.client.screen.v1;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
import net.minecraft.client.render.item.ItemRenderer;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.impl.client.screen.ScreenExtensions;
|
||||
import net.fabricmc.fabric.mixin.screen.ScreenAccessor;
|
||||
|
||||
/**
|
||||
* Utility methods related to screens.
|
||||
*
|
||||
* @see ScreenEvents
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class Screens {
|
||||
/**
|
||||
* Gets all of a screen's button widgets.
|
||||
* The provided list allows for addition and removal of buttons from the screen.
|
||||
* This method should be preferred over adding buttons directly to a screen's {@link Screen#children() child elements}.
|
||||
*
|
||||
* @return a list of all of a screen's buttons
|
||||
*/
|
||||
public static List<AbstractButtonWidget> getButtons(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ScreenExtensions.getExtensions(screen).fabric_getButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a screen's item renderer.
|
||||
*
|
||||
* @return the screen's item renderer
|
||||
*/
|
||||
public static ItemRenderer getItemRenderer(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ((ScreenAccessor) screen).getItemRenderer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a screen's text renderer.
|
||||
*
|
||||
* @return the screen's text renderer.
|
||||
*/
|
||||
public static TextRenderer getTextRenderer(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ((ScreenAccessor) screen).getTextRenderer();
|
||||
}
|
||||
|
||||
public static MinecraftClient getClient(Screen screen) {
|
||||
Objects.requireNonNull(screen, "Screen cannot be null");
|
||||
|
||||
return ((ScreenAccessor) screen).getClient();
|
||||
}
|
||||
|
||||
private Screens() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fabric Screen API v1.
|
||||
*
|
||||
* <p>The screen api provides events and utilities in this package are related to the lifecycle of a {@link net.minecraft.client.gui.screen.Screen}.
|
||||
*
|
||||
* <p>For general screen events see {@link net.fabricmc.fabric.api.client.screen.v1.ScreenEvents}.
|
||||
*
|
||||
* <p>For screen events related to the use of a mouse, see {@link net.fabricmc.fabric.api.client.screen.v1.ScreenMouseEvents}.
|
||||
*
|
||||
* <p>For screen events related to the use of a keyboard, see {@link net.fabricmc.fabric.api.client.screen.v1.ScreenKeyboardEvents}.
|
||||
*
|
||||
* @see net.fabricmc.fabric.api.client.screen.v1.Screens
|
||||
*/
|
||||
package net.fabricmc.fabric.api.client.screen.v1;
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.client.screen;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.client.gui.Element;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
// TODO: When events for listening to addition of child elements are added, fire events from this list.
|
||||
@ApiStatus.Internal
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ButtonList<T extends AbstractButtonWidget> extends AbstractList<T> {
|
||||
private final Screen screen;
|
||||
private final List<T> buttons;
|
||||
private final List<Element> children;
|
||||
|
||||
public ButtonList(Screen screen, List<T> buttons, List<Element> children) {
|
||||
this.screen = screen;
|
||||
this.buttons = buttons;
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int index) {
|
||||
return this.buttons.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T set(int index, T element) {
|
||||
this.remove(element); // verify / ensure no duplicates
|
||||
|
||||
final T existingButton = this.buttons.get(index);
|
||||
int elementIndex = this.children.indexOf(existingButton);
|
||||
|
||||
if (elementIndex > -1) {
|
||||
this.children.set(elementIndex, element);
|
||||
}
|
||||
|
||||
return this.buttons.set(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, T element) {
|
||||
this.rangeCheckForAdd(index); // verify index bounds
|
||||
this.remove(element); // ensure no duplicates
|
||||
|
||||
this.buttons.add(index, element);
|
||||
this.children.add(Math.min(this.children.size(), index), element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T remove(int index) {
|
||||
this.rangeCheck(index); // verify index bounds
|
||||
|
||||
final T removedButton = this.buttons.remove(index);
|
||||
this.children.remove(removedButton);
|
||||
|
||||
return removedButton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.buttons.size();
|
||||
}
|
||||
|
||||
private void rangeCheck(int index) {
|
||||
if (index >= this.size()) {
|
||||
throw createOutOfBoundsException(index);
|
||||
}
|
||||
}
|
||||
|
||||
private void rangeCheckForAdd(int index) {
|
||||
if (index > this.size() || index < 0) {
|
||||
throw createOutOfBoundsException(index);
|
||||
}
|
||||
}
|
||||
|
||||
private IndexOutOfBoundsException createOutOfBoundsException(int index) {
|
||||
return new IndexOutOfBoundsException("Index: " + index + ", Size: "+ this.size());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.client.screen;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenKeyboardEvents;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenMouseEvents;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
/**
|
||||
* Factory methods for creating event instances used in {@link ScreenExtensions}.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ScreenEventFactory {
|
||||
public static Event<ScreenEvents.Remove> createRemoveEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenEvents.Remove.class, callbacks -> screen -> {
|
||||
for (ScreenEvents.Remove callback : callbacks) {
|
||||
callback.onRemove(screen);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenEvents.BeforeRender> createBeforeRenderEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenEvents.BeforeRender.class, callbacks -> (screen, matrices, mouseX, mouseY, tickDelta) -> {
|
||||
for (ScreenEvents.BeforeRender callback : callbacks) {
|
||||
callback.beforeRender(screen, matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenEvents.AfterRender> createAfterRenderEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenEvents.AfterRender.class, callbacks -> (screen, matrices, mouseX, mouseY, tickDelta) -> {
|
||||
for (ScreenEvents.AfterRender callback : callbacks) {
|
||||
callback.afterRender(screen, matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenEvents.BeforeTick> createBeforeTickEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenEvents.BeforeTick.class, callbacks -> screen -> {
|
||||
for (ScreenEvents.BeforeTick callback : callbacks) {
|
||||
callback.beforeTick(screen);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenEvents.AfterTick> createAfterTickEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenEvents.AfterTick.class, callbacks -> screen -> {
|
||||
for (ScreenEvents.AfterTick callback : callbacks) {
|
||||
callback.afterTick(screen);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Keyboard events
|
||||
|
||||
public static Event<ScreenKeyboardEvents.AllowKeyPress> createAllowKeyPressEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenKeyboardEvents.AllowKeyPress.class, callbacks -> (screen, key, scancode, modifiers) -> {
|
||||
for (ScreenKeyboardEvents.AllowKeyPress callback : callbacks) {
|
||||
if (!callback.allowKeyPress(screen, key, scancode, modifiers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenKeyboardEvents.BeforeKeyPress> createBeforeKeyPressEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenKeyboardEvents.BeforeKeyPress.class, callbacks -> (screen, key, scancode, modifiers) -> {
|
||||
for (ScreenKeyboardEvents.BeforeKeyPress callback : callbacks) {
|
||||
callback.beforeKeyPress(screen, key, scancode, modifiers);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenKeyboardEvents.AfterKeyPress> createAfterKeyPressEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenKeyboardEvents.AfterKeyPress.class, callbacks -> (screen, key, scancode, modifiers) -> {
|
||||
for (ScreenKeyboardEvents.AfterKeyPress callback : callbacks) {
|
||||
callback.afterKeyPress(screen, key, scancode, modifiers);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenKeyboardEvents.AllowKeyRelease> createAllowKeyReleaseEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenKeyboardEvents.AllowKeyRelease.class, callbacks -> (screen, key, scancode, modifiers) -> {
|
||||
for (ScreenKeyboardEvents.AllowKeyRelease callback : callbacks) {
|
||||
if (!callback.allowKeyRelease(screen, key, scancode, modifiers)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenKeyboardEvents.BeforeKeyRelease> createBeforeKeyReleaseEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenKeyboardEvents.BeforeKeyRelease.class, callbacks -> (screen, key, scancode, modifiers) -> {
|
||||
for (ScreenKeyboardEvents.BeforeKeyRelease callback : callbacks) {
|
||||
callback.beforeKeyRelease(screen, key, scancode, modifiers);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenKeyboardEvents.AfterKeyRelease> createAfterKeyReleaseEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenKeyboardEvents.AfterKeyRelease.class, callbacks -> (screen, key, scancode, modifiers) -> {
|
||||
for (ScreenKeyboardEvents.AfterKeyRelease callback : callbacks) {
|
||||
callback.afterKeyRelease(screen, key, scancode, modifiers);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Mouse Events
|
||||
|
||||
public static Event<ScreenMouseEvents.AllowMouseClick> createAllowMouseClickEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenMouseEvents.AllowMouseClick.class, callbacks -> (screen, mouseX, mouseY, button) -> {
|
||||
for (ScreenMouseEvents.AllowMouseClick callback : callbacks) {
|
||||
if (!callback.allowMouseClick(screen, mouseX, mouseY, button)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenMouseEvents.BeforeMouseClick> createBeforeMouseClickEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenMouseEvents.BeforeMouseClick.class, callbacks -> (screen, mouseX, mouseY, button) -> {
|
||||
for (ScreenMouseEvents.BeforeMouseClick callback : callbacks) {
|
||||
callback.beforeMouseClick(screen, mouseX, mouseY, button);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenMouseEvents.AfterMouseClick> createAfterMouseClickEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenMouseEvents.AfterMouseClick.class, callbacks -> (screen, mouseX, mouseY, button) -> {
|
||||
for (ScreenMouseEvents.AfterMouseClick callback : callbacks) {
|
||||
callback.afterMouseClick(screen, mouseX, mouseY, button);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenMouseEvents.AllowMouseRelease> createAllowMouseReleaseEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenMouseEvents.AllowMouseRelease.class, callbacks -> (screen, mouseX, mouseY, button) -> {
|
||||
for (ScreenMouseEvents.AllowMouseRelease callback : callbacks) {
|
||||
if (!callback.allowMouseRelease(screen, mouseX, mouseY, button)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenMouseEvents.BeforeMouseRelease> createBeforeMouseReleaseEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenMouseEvents.BeforeMouseRelease.class, callbacks -> (screen, mouseX, mouseY, button) -> {
|
||||
for (ScreenMouseEvents.BeforeMouseRelease callback : callbacks) {
|
||||
callback.beforeMouseRelease(screen, mouseX, mouseY, button);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenMouseEvents.AfterMouseRelease> createAfterMouseReleaseEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenMouseEvents.AfterMouseRelease.class, callbacks -> (screen, mouseX, mouseY, button) -> {
|
||||
for (ScreenMouseEvents.AfterMouseRelease callback : callbacks) {
|
||||
callback.afterMouseRelease(screen, mouseX, mouseY, button);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenMouseEvents.AllowMouseScroll> createAllowMouseScrollEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenMouseEvents.AllowMouseScroll.class, callbacks -> (screen, mouseX, mouseY, horizontalAmount, verticalAmount) -> {
|
||||
for (ScreenMouseEvents.AllowMouseScroll callback : callbacks) {
|
||||
if (!callback.allowMouseScroll(screen, mouseX, mouseY, horizontalAmount, verticalAmount)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenMouseEvents.BeforeMouseScroll> createBeforeMouseScrollEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenMouseEvents.BeforeMouseScroll.class, callbacks -> (screen, mouseX, mouseY, horizontalAmount, verticalAmount) -> {
|
||||
for (ScreenMouseEvents.BeforeMouseScroll callback : callbacks) {
|
||||
callback.beforeMouseScroll(screen, mouseX, mouseY, horizontalAmount, verticalAmount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Event<ScreenMouseEvents.AfterMouseScroll> createAfterMouseScrollEvent() {
|
||||
return EventFactory.createArrayBacked(ScreenMouseEvents.AfterMouseScroll.class, callbacks -> (screen, mouseX, mouseY, horizontalAmount, verticalAmount) -> {
|
||||
for (ScreenMouseEvents.AfterMouseScroll callback : callbacks) {
|
||||
callback.afterMouseScroll(screen, mouseX, mouseY, horizontalAmount, verticalAmount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ScreenEventFactory() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.client.screen;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenKeyboardEvents;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenMouseEvents;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Environment(EnvType.CLIENT)
|
||||
public interface ScreenExtensions {
|
||||
static ScreenExtensions getExtensions(Screen screen) {
|
||||
return (ScreenExtensions) screen;
|
||||
}
|
||||
|
||||
List<AbstractButtonWidget> fabric_getButtons();
|
||||
|
||||
Event<ScreenEvents.Remove> fabric_getRemoveEvent();
|
||||
|
||||
Event<ScreenEvents.BeforeTick> fabric_getBeforeTickEvent();
|
||||
|
||||
Event<ScreenEvents.AfterTick> fabric_getAfterTickEvent();
|
||||
|
||||
Event<ScreenEvents.BeforeRender> fabric_getBeforeRenderEvent();
|
||||
|
||||
Event<ScreenEvents.AfterRender> fabric_getAfterRenderEvent();
|
||||
|
||||
// Keyboard
|
||||
|
||||
Event<ScreenKeyboardEvents.AllowKeyPress> fabric_getAllowKeyPressEvent();
|
||||
|
||||
Event<ScreenKeyboardEvents.BeforeKeyPress> fabric_getBeforeKeyPressEvent();
|
||||
|
||||
Event<ScreenKeyboardEvents.AfterKeyPress> fabric_getAfterKeyPressEvent();
|
||||
|
||||
Event<ScreenKeyboardEvents.AllowKeyRelease> fabric_getAllowKeyReleaseEvent();
|
||||
|
||||
Event<ScreenKeyboardEvents.BeforeKeyRelease> fabric_getBeforeKeyReleaseEvent();
|
||||
|
||||
Event<ScreenKeyboardEvents.AfterKeyRelease> fabric_getAfterKeyReleaseEvent();
|
||||
|
||||
// Mouse
|
||||
|
||||
Event<ScreenMouseEvents.AllowMouseClick> fabric_getAllowMouseClickEvent();
|
||||
|
||||
Event<ScreenMouseEvents.BeforeMouseClick> fabric_getBeforeMouseClickEvent();
|
||||
|
||||
Event<ScreenMouseEvents.AfterMouseClick> fabric_getAfterMouseClickEvent();
|
||||
|
||||
Event<ScreenMouseEvents.AllowMouseRelease> fabric_getAllowMouseReleaseEvent();
|
||||
|
||||
Event<ScreenMouseEvents.BeforeMouseRelease> fabric_getBeforeMouseReleaseEvent();
|
||||
|
||||
Event<ScreenMouseEvents.AfterMouseRelease> fabric_getAfterMouseReleaseEvent();
|
||||
|
||||
Event<ScreenMouseEvents.AllowMouseScroll> fabric_getAllowMouseScrollEvent();
|
||||
|
||||
Event<ScreenMouseEvents.BeforeMouseScroll> fabric_getBeforeMouseScrollEvent();
|
||||
|
||||
Event<ScreenMouseEvents.AfterMouseScroll> fabric_getAfterMouseScrollEvent();
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.screen;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(GameRenderer.class)
|
||||
abstract class GameRendererMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private MinecraftClient client;
|
||||
|
||||
@Unique
|
||||
private Screen renderingScreen;
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;render(Lnet/minecraft/client/util/math/MatrixStack;IIF)V"), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
private void onBeforeRenderScreen(float tickDelta, long startTime, boolean tick, CallbackInfo ci, int mouseX, int mouseY, MatrixStack matrices) {
|
||||
// Store the screen in a variable in case someone tries to change the screen during this before render event.
|
||||
// If someone changes the screen, the after render event will likely have class cast exceptions or an NPE.
|
||||
this.renderingScreen = this.client.currentScreen;
|
||||
ScreenEvents.beforeRender(this.renderingScreen).invoker().beforeRender(this.renderingScreen, matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
|
||||
// This injection should end up in the try block so exceptions are caught
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;render(Lnet/minecraft/client/util/math/MatrixStack;IIF)V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
private void onAfterRenderScreen(float tickDelta, long startTime, boolean tick, CallbackInfo ci, int mouseX, int mouseY, MatrixStack matrices) {
|
||||
ScreenEvents.afterRender(this.renderingScreen).invoker().afterRender(this.renderingScreen, matrices, mouseX, mouseY, tickDelta);
|
||||
// Finally set the currently rendering screen to null
|
||||
this.renderingScreen = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.screen;
|
||||
|
||||
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;
|
||||
|
||||
import net.minecraft.client.Keyboard;
|
||||
import net.minecraft.client.gui.ParentElement;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenKeyboardEvents;
|
||||
|
||||
@Mixin(Keyboard.class)
|
||||
abstract class KeyboardMixin {
|
||||
// private synthetic method_1454(I[ZLnet/minecraft/client/gui/ParentElement;III)V
|
||||
@Inject(method = "method_1454(I[ZLnet/minecraft/client/gui/ParentElement;III)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/ParentElement;keyPressed(III)Z"), cancellable = true)
|
||||
private void beforeKeyPressedEvent(int code, boolean[] resultHack, ParentElement parentElement, int key, int scancode, int modifiers, CallbackInfo ci) {
|
||||
final Screen screen = (Screen) parentElement;
|
||||
|
||||
if (!ScreenKeyboardEvents.allowKeyPress(screen).invoker().allowKeyPress(screen, key, scancode, modifiers)) {
|
||||
resultHack[0] = true; // Set this press action as handled.
|
||||
ci.cancel(); // Exit the lambda
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenKeyboardEvents.beforeKeyPress(screen).invoker().beforeKeyPress(screen, key, scancode, modifiers);
|
||||
}
|
||||
|
||||
// private synthetic method_1454(I[ZLnet/minecraft/client/gui/ParentElement;III)V
|
||||
@Inject(method = "method_1454(I[ZLnet/minecraft/client/gui/ParentElement;III)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/ParentElement;keyPressed(III)Z", shift = At.Shift.AFTER))
|
||||
private void afterKeyPressedEvent(int code, boolean[] resultHack, ParentElement parentElement, int key, int scancode, int modifiers, CallbackInfo ci) {
|
||||
final Screen screen = (Screen) parentElement;
|
||||
ScreenKeyboardEvents.afterKeyPress(screen).invoker().afterKeyPress(screen, key, scancode, modifiers);
|
||||
}
|
||||
|
||||
// private synthetic method_1454(I[ZLnet/minecraft/client/gui/ParentElement;III)V
|
||||
@Inject(method = "method_1454(I[ZLnet/minecraft/client/gui/ParentElement;III)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/ParentElement;keyReleased(III)Z"), cancellable = true)
|
||||
private void beforeKeyReleasedEvent(int code, boolean[] resultHack, ParentElement parentElement, int key, int scancode, int modifiers, CallbackInfo ci) {
|
||||
final Screen screen = (Screen) parentElement;
|
||||
|
||||
if (!ScreenKeyboardEvents.allowKeyRelease(screen).invoker().allowKeyRelease(screen, key, scancode, modifiers)) {
|
||||
resultHack[0] = true; // Set this press action as handled.
|
||||
ci.cancel(); // Exit the lambda
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenKeyboardEvents.beforeKeyRelease(screen).invoker().beforeKeyRelease(screen, key, scancode, modifiers);
|
||||
}
|
||||
|
||||
// private synthetic method_1454(I[ZLnet/minecraft/client/gui/ParentElement;III)V
|
||||
@Inject(method = "method_1454(I[ZLnet/minecraft/client/gui/ParentElement;III)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/ParentElement;keyReleased(III)Z", shift = At.Shift.AFTER))
|
||||
private void afterKeyReleasedEvent(int code, boolean[] resultHack, ParentElement parentElement, int key, int scancode, int modifiers, CallbackInfo ci) {
|
||||
final Screen screen = (Screen) parentElement;
|
||||
ScreenKeyboardEvents.afterKeyRelease(screen).invoker().afterKeyRelease(screen, key, scancode, modifiers);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.screen;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
abstract class MinecraftClientMixin {
|
||||
@Shadow
|
||||
public Screen currentScreen;
|
||||
|
||||
@Unique
|
||||
private Screen tickingScreen;
|
||||
|
||||
@Inject(method = "openScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;removed()V", shift = At.Shift.AFTER))
|
||||
private void onScreenRemove(@Nullable Screen screen, CallbackInfo ci) {
|
||||
ScreenEvents.remove(this.currentScreen).invoker().onRemove(this.currentScreen);
|
||||
}
|
||||
|
||||
@Inject(method = "stop", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;removed()V", shift = At.Shift.AFTER))
|
||||
private void onScreenRemoveBecauseStopping(CallbackInfo ci) {
|
||||
ScreenEvents.remove(this.currentScreen).invoker().onRemove(this.currentScreen);
|
||||
}
|
||||
|
||||
// Synthetic method in `tick`
|
||||
// These two injections should be caught by "Screen#wrapScreenError" if anything fails in an event and then rethrown in the crash report
|
||||
@Inject(method = "method_1572", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;tick()V"))
|
||||
private void beforeScreenTick(CallbackInfo ci) {
|
||||
// Store the screen in a variable in case someone tries to change the screen during this before tick event.
|
||||
// If someone changes the screen, the after tick event will likely have class cast exceptions or an NPE.
|
||||
this.tickingScreen = this.currentScreen;
|
||||
ScreenEvents.beforeTick(this.tickingScreen).invoker().beforeTick(this.tickingScreen);
|
||||
}
|
||||
|
||||
// Synthetic method in `tick`
|
||||
@Inject(method = "method_1572", at = @At("TAIL"))
|
||||
private void afterScreenTick(CallbackInfo ci) {
|
||||
ScreenEvents.afterTick(this.tickingScreen).invoker().afterTick(this.tickingScreen);
|
||||
// Finally set the currently ticking screen to null
|
||||
this.tickingScreen = null;
|
||||
}
|
||||
|
||||
// The LevelLoadingScreen is the odd screen that isn't ticked by the main tick loop, so we fire events for this screen.
|
||||
// We Coerce the package-private inner class representing the world load action so we don't need an access widener.
|
||||
@Inject(method = "startIntegratedServer(Ljava/lang/String;Lnet/minecraft/util/registry/DynamicRegistryManager$Impl;Ljava/util/function/Function;Lcom/mojang/datafixers/util/Function4;ZLnet/minecraft/client/MinecraftClient$WorldLoadAction;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/LevelLoadingScreen;tick()V"))
|
||||
private void beforeLoadingScreenTick(CallbackInfo ci) {
|
||||
// Store the screen in a variable in case someone tries to change the screen during this before tick event.
|
||||
// If someone changes the screen, the after tick event will likely have class cast exceptions or throw a NPE.
|
||||
this.tickingScreen = this.currentScreen;
|
||||
ScreenEvents.beforeTick(this.tickingScreen).invoker().beforeTick(this.tickingScreen);
|
||||
}
|
||||
|
||||
@Inject(method = "startIntegratedServer(Ljava/lang/String;Lnet/minecraft/util/registry/DynamicRegistryManager$Impl;Ljava/util/function/Function;Lcom/mojang/datafixers/util/Function4;ZLnet/minecraft/client/MinecraftClient$WorldLoadAction;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;render(Z)V"))
|
||||
private void afterLoadingScreenTick(CallbackInfo ci) {
|
||||
ScreenEvents.afterTick(this.tickingScreen).invoker().afterTick(this.tickingScreen);
|
||||
// Finally set the currently ticking screen to null
|
||||
this.tickingScreen = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.screen;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.Mouse;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenMouseEvents;
|
||||
|
||||
@Mixin(Mouse.class)
|
||||
abstract class MouseMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private MinecraftClient client;
|
||||
@Unique
|
||||
private Screen currentScreen;
|
||||
@Unique
|
||||
private Double horizontalScrollAmount;
|
||||
|
||||
// private synthetic method_1611([ZDDI)V
|
||||
@Inject(method = "method_1611([ZDDI)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseClicked(DDI)Z"), cancellable = true)
|
||||
private void beforeMouseClickedEvent(boolean[] resultHack, double mouseX, double mouseY, int button, CallbackInfo ci) {
|
||||
// Store the screen in a variable in case someone tries to change the screen during this before event.
|
||||
// If someone changes the screen, the after event will likely have class cast exceptions or throw a NPE.
|
||||
this.currentScreen = this.client.currentScreen;
|
||||
|
||||
if (this.currentScreen == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ScreenMouseEvents.allowMouseClick(this.currentScreen).invoker().allowMouseClick(this.currentScreen, mouseX, mouseY, button)) {
|
||||
resultHack[0] = true; // Set this press action as handled.
|
||||
this.currentScreen = null;
|
||||
ci.cancel(); // Exit the lambda
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenMouseEvents.beforeMouseClick(this.currentScreen).invoker().beforeMouseClick(this.currentScreen, mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
// private synthetic method_1611([ZDDI)V
|
||||
@Inject(method = "method_1611([ZDDI)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseClicked(DDI)Z", shift = At.Shift.AFTER))
|
||||
private void afterMouseClickedEvent(boolean[] resultHack, double mouseX, double mouseY, int button, CallbackInfo ci) {
|
||||
if (this.currentScreen == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenMouseEvents.afterMouseClick(this.currentScreen).invoker().afterMouseClick(this.currentScreen, mouseX, mouseY, button);
|
||||
this.currentScreen = null;
|
||||
}
|
||||
|
||||
// private synthetic method_1605([ZDDI)V
|
||||
@Inject(method = "method_1605([ZDDI)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseReleased(DDI)Z"), cancellable = true)
|
||||
private void beforeMouseReleasedEvent(boolean[] resultHack, double mouseX, double mouseY, int button, CallbackInfo ci) {
|
||||
// Store the screen in a variable in case someone tries to change the screen during this before event.
|
||||
// If someone changes the screen, the after event will likely have class cast exceptions or throw a NPE.
|
||||
this.currentScreen = this.client.currentScreen;
|
||||
|
||||
if (this.currentScreen == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ScreenMouseEvents.allowMouseRelease(this.currentScreen).invoker().allowMouseRelease(this.currentScreen, mouseX, mouseY, button)) {
|
||||
resultHack[0] = true; // Set this press action as handled.
|
||||
this.currentScreen = null;
|
||||
ci.cancel(); // Exit the lambda
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenMouseEvents.beforeMouseRelease(this.currentScreen).invoker().beforeMouseRelease(this.currentScreen, mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
// private synthetic method_1605([ZDDI)V
|
||||
@Inject(method = "method_1605([ZDDI)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseReleased(DDI)Z", shift = At.Shift.AFTER))
|
||||
private void afterMouseReleasedEvent(boolean[] resultHack, double mouseX, double mouseY, int button, CallbackInfo ci) {
|
||||
if (this.currentScreen == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenMouseEvents.afterMouseRelease(this.currentScreen).invoker().afterMouseRelease(this.currentScreen, mouseX, mouseY, button);
|
||||
this.currentScreen = null;
|
||||
}
|
||||
|
||||
@Inject(method = "onMouseScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseScrolled(DDD)Z"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true)
|
||||
private void beforeMouseScrollEvent(long window, double horizontal, double vertical, CallbackInfo ci, double verticalAmount, double mouseX, double mouseY) {
|
||||
// Store the screen in a variable in case someone tries to change the screen during this before event.
|
||||
// If someone changes the screen, the after event will likely have class cast exceptions or throw a NPE.
|
||||
this.currentScreen = this.client.currentScreen;
|
||||
|
||||
if (this.currentScreen == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply same calculations to horizontal scroll as vertical scroll amount has
|
||||
this.horizontalScrollAmount = this.client.options.discreteMouseScroll ? Math.signum(horizontal) : horizontal * this.client.options.mouseWheelSensitivity;
|
||||
|
||||
if (!ScreenMouseEvents.allowMouseScroll(this.currentScreen).invoker().allowMouseScroll(this.currentScreen, mouseX, mouseY, this.horizontalScrollAmount, verticalAmount)) {
|
||||
this.currentScreen = null;
|
||||
this.horizontalScrollAmount = null;
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenMouseEvents.beforeMouseScroll(this.currentScreen).invoker().beforeMouseScroll(this.currentScreen, mouseX, mouseY, this.horizontalScrollAmount, verticalAmount);
|
||||
}
|
||||
|
||||
@Inject(method = "onMouseScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseScrolled(DDD)Z", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
private void afterMouseScrollEvent(long window, double horizontal, double vertical, CallbackInfo ci, double verticalAmount, double mouseX, double mouseY) {
|
||||
if (this.currentScreen == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenMouseEvents.afterMouseScroll(this.currentScreen).invoker().afterMouseScroll(this.currentScreen, mouseX, mouseY, this.horizontalScrollAmount, verticalAmount);
|
||||
this.currentScreen = null;
|
||||
this.horizontalScrollAmount = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.screen;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.render.item.ItemRenderer;
|
||||
|
||||
@Mixin(Screen.class)
|
||||
public interface ScreenAccessor {
|
||||
@Accessor
|
||||
ItemRenderer getItemRenderer();
|
||||
|
||||
@Accessor
|
||||
TextRenderer getTextRenderer();
|
||||
|
||||
@Accessor
|
||||
MinecraftClient getClient();
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.screen;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.Element;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||
import net.fabricmc.fabric.impl.client.screen.ScreenExtensions;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenKeyboardEvents;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenMouseEvents;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.impl.client.screen.ButtonList;
|
||||
import net.fabricmc.fabric.impl.client.screen.ScreenEventFactory;
|
||||
|
||||
@Mixin(Screen.class)
|
||||
abstract class ScreenMixin implements ScreenExtensions {
|
||||
@Shadow
|
||||
@Final
|
||||
protected List<AbstractButtonWidget> buttons;
|
||||
@Shadow
|
||||
@Final
|
||||
protected List<Element> children;
|
||||
|
||||
@Unique
|
||||
private ButtonList<AbstractButtonWidget> fabricButtons;
|
||||
@Unique
|
||||
private Event<ScreenEvents.Remove> removeEvent;
|
||||
@Unique
|
||||
private Event<ScreenEvents.BeforeTick> beforeTickEvent;
|
||||
@Unique
|
||||
private Event<ScreenEvents.AfterTick> afterTickEvent;
|
||||
@Unique
|
||||
private Event<ScreenEvents.BeforeRender> beforeRenderEvent;
|
||||
@Unique
|
||||
private Event<ScreenEvents.AfterRender> afterRenderEvent;
|
||||
|
||||
// Keyboard
|
||||
@Unique
|
||||
private Event<ScreenKeyboardEvents.AllowKeyPress> allowKeyPressEvent;
|
||||
@Unique
|
||||
private Event<ScreenKeyboardEvents.BeforeKeyPress> beforeKeyPressEvent;
|
||||
@Unique
|
||||
private Event<ScreenKeyboardEvents.AfterKeyPress> afterKeyPressEvent;
|
||||
@Unique
|
||||
private Event<ScreenKeyboardEvents.AllowKeyRelease> allowKeyReleaseEvent;
|
||||
@Unique
|
||||
private Event<ScreenKeyboardEvents.BeforeKeyRelease> beforeKeyReleaseEvent;
|
||||
@Unique
|
||||
private Event<ScreenKeyboardEvents.AfterKeyRelease> afterKeyReleaseEvent;
|
||||
|
||||
// Mouse
|
||||
@Unique
|
||||
private Event<ScreenMouseEvents.AllowMouseClick> allowMouseClickEvent;
|
||||
@Unique
|
||||
private Event<ScreenMouseEvents.BeforeMouseClick> beforeMouseClickEvent;
|
||||
@Unique
|
||||
private Event<ScreenMouseEvents.AfterMouseClick> afterMouseClickEvent;
|
||||
@Unique
|
||||
private Event<ScreenMouseEvents.AllowMouseRelease> allowMouseReleaseEvent;
|
||||
@Unique
|
||||
private Event<ScreenMouseEvents.BeforeMouseRelease> beforeMouseReleaseEvent;
|
||||
@Unique
|
||||
private Event<ScreenMouseEvents.AfterMouseRelease> afterMouseReleaseEvent;
|
||||
@Unique
|
||||
private Event<ScreenMouseEvents.AllowMouseScroll> allowMouseScrollEvent;
|
||||
@Unique
|
||||
private Event<ScreenMouseEvents.BeforeMouseScroll> beforeMouseScrollEvent;
|
||||
@Unique
|
||||
private Event<ScreenMouseEvents.AfterMouseScroll> afterMouseScrollEvent;
|
||||
|
||||
@Inject(method = "init(Lnet/minecraft/client/MinecraftClient;II)V", at = @At("HEAD"))
|
||||
private void beforeInitScreen(MinecraftClient client, int width, int height, CallbackInfo ci) {
|
||||
// All elements are repopulated on the screen, so we need to reinitialize all events
|
||||
this.fabricButtons = null;
|
||||
this.removeEvent = ScreenEventFactory.createRemoveEvent();
|
||||
this.beforeRenderEvent = ScreenEventFactory.createBeforeRenderEvent();
|
||||
this.afterRenderEvent = ScreenEventFactory.createAfterRenderEvent();
|
||||
this.beforeTickEvent = ScreenEventFactory.createBeforeTickEvent();
|
||||
this.afterTickEvent = ScreenEventFactory.createAfterTickEvent();
|
||||
|
||||
// Keyboard
|
||||
this.allowKeyPressEvent = ScreenEventFactory.createAllowKeyPressEvent();
|
||||
this.beforeKeyPressEvent = ScreenEventFactory.createBeforeKeyPressEvent();
|
||||
this.afterKeyPressEvent = ScreenEventFactory.createAfterKeyPressEvent();
|
||||
this.allowKeyReleaseEvent = ScreenEventFactory.createAllowKeyReleaseEvent();
|
||||
this.beforeKeyReleaseEvent = ScreenEventFactory.createBeforeKeyReleaseEvent();
|
||||
this.afterKeyReleaseEvent = ScreenEventFactory.createAfterKeyReleaseEvent();
|
||||
|
||||
// Mouse
|
||||
this.allowMouseClickEvent = ScreenEventFactory.createAllowMouseClickEvent();
|
||||
this.beforeMouseClickEvent = ScreenEventFactory.createBeforeMouseClickEvent();
|
||||
this.afterMouseClickEvent = ScreenEventFactory.createAfterMouseClickEvent();
|
||||
this.allowMouseReleaseEvent = ScreenEventFactory.createAllowMouseReleaseEvent();
|
||||
this.beforeMouseReleaseEvent = ScreenEventFactory.createBeforeMouseReleaseEvent();
|
||||
this.afterMouseReleaseEvent = ScreenEventFactory.createAfterMouseReleaseEvent();
|
||||
this.allowMouseScrollEvent = ScreenEventFactory.createAllowMouseScrollEvent();
|
||||
this.beforeMouseScrollEvent = ScreenEventFactory.createBeforeMouseScrollEvent();
|
||||
this.afterMouseScrollEvent = ScreenEventFactory.createAfterMouseScrollEvent();
|
||||
|
||||
ScreenEvents.BEFORE_INIT.invoker().beforeInit(client, (Screen) (Object) this, width, height);
|
||||
}
|
||||
|
||||
@Inject(method = "init(Lnet/minecraft/client/MinecraftClient;II)V", at = @At("TAIL"))
|
||||
private void afterInitScreen(MinecraftClient client, int width, int height, CallbackInfo ci) {
|
||||
ScreenEvents.AFTER_INIT.invoker().afterInit(client, (Screen) (Object) this, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AbstractButtonWidget> fabric_getButtons() {
|
||||
// Lazy init to make the list access safe after Screen#init
|
||||
if (this.fabricButtons == null) {
|
||||
this.fabricButtons = new ButtonList<>((Screen) (Object) this, this.buttons, this.children);
|
||||
}
|
||||
|
||||
return this.fabricButtons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenEvents.Remove> fabric_getRemoveEvent() {
|
||||
return this.removeEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenEvents.BeforeTick> fabric_getBeforeTickEvent() {
|
||||
return this.beforeTickEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenEvents.AfterTick> fabric_getAfterTickEvent() {
|
||||
return this.afterTickEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenEvents.BeforeRender> fabric_getBeforeRenderEvent() {
|
||||
return this.beforeRenderEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenEvents.AfterRender> fabric_getAfterRenderEvent() {
|
||||
return this.afterRenderEvent;
|
||||
}
|
||||
|
||||
// Keyboard
|
||||
|
||||
@Override
|
||||
public Event<ScreenKeyboardEvents.AllowKeyPress> fabric_getAllowKeyPressEvent() {
|
||||
return this.allowKeyPressEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenKeyboardEvents.BeforeKeyPress> fabric_getBeforeKeyPressEvent() {
|
||||
return this.beforeKeyPressEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenKeyboardEvents.AfterKeyPress> fabric_getAfterKeyPressEvent() {
|
||||
return this.afterKeyPressEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenKeyboardEvents.AllowKeyRelease> fabric_getAllowKeyReleaseEvent() {
|
||||
return this.allowKeyReleaseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenKeyboardEvents.BeforeKeyRelease> fabric_getBeforeKeyReleaseEvent() {
|
||||
return this.beforeKeyReleaseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenKeyboardEvents.AfterKeyRelease> fabric_getAfterKeyReleaseEvent() {
|
||||
return this.afterKeyReleaseEvent;
|
||||
}
|
||||
|
||||
// Mouse
|
||||
|
||||
@Override
|
||||
public Event<ScreenMouseEvents.AllowMouseClick> fabric_getAllowMouseClickEvent() {
|
||||
return this.allowMouseClickEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenMouseEvents.BeforeMouseClick> fabric_getBeforeMouseClickEvent() {
|
||||
return this.beforeMouseClickEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenMouseEvents.AfterMouseClick> fabric_getAfterMouseClickEvent() {
|
||||
return this.afterMouseClickEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenMouseEvents.AllowMouseRelease> fabric_getAllowMouseReleaseEvent() {
|
||||
return this.allowMouseReleaseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenMouseEvents.BeforeMouseRelease> fabric_getBeforeMouseReleaseEvent() {
|
||||
return this.beforeMouseReleaseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenMouseEvents.AfterMouseRelease> fabric_getAfterMouseReleaseEvent() {
|
||||
return this.afterMouseReleaseEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenMouseEvents.AllowMouseScroll> fabric_getAllowMouseScrollEvent() {
|
||||
return this.allowMouseScrollEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenMouseEvents.BeforeMouseScroll> fabric_getBeforeMouseScrollEvent() {
|
||||
return this.beforeMouseScrollEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ScreenMouseEvents.AfterMouseScroll> fabric_getAfterMouseScrollEvent() {
|
||||
return this.afterMouseScrollEvent;
|
||||
}
|
||||
}
|
Binary file not shown.
After ![]() (image error) Size: 1.5 KiB |
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.screen",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"client": [
|
||||
"GameRendererMixin",
|
||||
"MinecraftClientMixin",
|
||||
"ScreenMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"mixins": [
|
||||
"KeyboardMixin",
|
||||
"MouseMixin",
|
||||
"ScreenAccessor"
|
||||
]
|
||||
}
|
29
fabric-screen-api-v1/src/main/resources/fabric.mod.json
Normal file
29
fabric-screen-api-v1/src/main/resources/fabric.mod.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-screen-api-v1",
|
||||
"name": "Fabric Screen API (v1)",
|
||||
"version": "${version}",
|
||||
"environment": "client",
|
||||
"license": "Apache-2.0",
|
||||
"icon": "assets/fabric-screen-api-v1/icon.png",
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net",
|
||||
"irc": "irc://irc.esper.net:6667/fabric",
|
||||
"issues": "https://github.com/FabricMC/fabric/issues",
|
||||
"sources": "https://github.com/FabricMC/fabric"
|
||||
},
|
||||
"authors": [
|
||||
"FabricMC"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.8.2",
|
||||
"fabric-api-base": "*"
|
||||
},
|
||||
"description": "Adds screen related hooks.",
|
||||
"mixins": [
|
||||
"fabric-screen-api-v1.mixins.json"
|
||||
],
|
||||
"custom": {
|
||||
"fabric-api:module-lifecycle": "stable"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.screen;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.DrawableHelper;
|
||||
import net.minecraft.client.gui.hud.InGameHud;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.TitleScreen;
|
||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenKeyboardEvents;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.Screens;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final class ScreenTests implements ClientModInitializer {
|
||||
private static final Logger LOGGER = LogManager.getLogger("FabricScreenApiTests");
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
LOGGER.info("Started Screen Testmod");
|
||||
ScreenEvents.BEFORE_INIT.register((client, screen, width, height) -> {
|
||||
// TODO: Write tests listening to addition of child elements
|
||||
});
|
||||
|
||||
ScreenEvents.AFTER_INIT.register(this::afterInitScreen);
|
||||
}
|
||||
|
||||
private void afterInitScreen(MinecraftClient client, Screen screen, int windowWidth, int windowHeight) {
|
||||
LOGGER.info("Initializing {}", screen.getClass().getName());
|
||||
|
||||
if (screen instanceof TitleScreen) {
|
||||
final List<AbstractButtonWidget> buttons = Screens.getButtons(screen);
|
||||
|
||||
// Shrink the realms button, should be the third button on the list
|
||||
final AbstractButtonWidget optionsButton = buttons.get(2);
|
||||
optionsButton.setWidth(98);
|
||||
|
||||
// Add a new button
|
||||
buttons.add(new SoundButton((screen.width / 2) + 2, ((screen.height / 4) + 96), 72, 20));
|
||||
// And another button
|
||||
buttons.add(new StopSoundButton(screen, (screen.width / 2) + 80, ((screen.height / 4) + 95), 20, 20));
|
||||
|
||||
// Testing:
|
||||
// Some automatic validation that the screen list works, make sure the buttons we added are on the list of child elements
|
||||
screen.children().stream()
|
||||
.filter(element -> element instanceof SoundButton)
|
||||
.findAny()
|
||||
.orElseThrow(() -> new AssertionError("Failed to find the \"Sound\" button in the screen's elements"));
|
||||
|
||||
screen.children().stream()
|
||||
.filter(element -> element instanceof StopSoundButton)
|
||||
.findAny()
|
||||
.orElseThrow(() -> new AssertionError("Failed to find the \"Stop Sound\" button in the screen's elements"));
|
||||
|
||||
// Register render event to draw an icon on the screen
|
||||
ScreenEvents.afterRender(screen).register((_screen, matrices, mouseX, mouseY, tickDelta) -> {
|
||||
// Render an armor icon to test
|
||||
client.getTextureManager().bindTexture(InGameHud.GUI_ICONS_TEXTURE);
|
||||
DrawableHelper.drawTexture(matrices, (screen.width / 2) - 124, (screen.height / 4) + 96, 20, 20, 34, 9, 9, 9, 256, 256);
|
||||
});
|
||||
|
||||
ScreenKeyboardEvents.allowKeyPress(screen).register((_screen, key, scancode, modifiers) -> {
|
||||
LOGGER.info("After Pressed, Code: {}, Scancode: {}, Modifiers: {}", key, scancode, modifiers);
|
||||
return false; // Let actions continue
|
||||
});
|
||||
|
||||
ScreenKeyboardEvents.afterKeyPress(screen).register((_screen, key, scancode, modifiers) -> {
|
||||
LOGGER.warn("Pressed, Code: {}, Scancode: {}, Modifiers: {}", key, scancode, modifiers);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.screen;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
|
||||
import net.minecraft.client.sound.PositionedSoundInstance;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.SimpleRegistry;
|
||||
|
||||
class SoundButton extends AbstractPressableButtonWidget {
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
SoundButton(int x, int y, int width, int height) {
|
||||
super(x, y, width, height, Text.of("Sound Button"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPress() {
|
||||
// Upcast on registry is fine
|
||||
@Nullable
|
||||
final SoundEvent event = ((SimpleRegistry<SoundEvent>) Registry.SOUND_EVENT).getRandom(RANDOM);
|
||||
|
||||
MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(event != null ? event : SoundEvents.ENTITY_GENERIC_EXPLODE, 1.0F, 1.0F));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.test.screen;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.DrawableHelper;
|
||||
import net.minecraft.client.gui.hud.InGameHud;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
class StopSoundButton extends AbstractPressableButtonWidget {
|
||||
private final Screen screen;
|
||||
|
||||
StopSoundButton(Screen screen, int x, int y, int width, int height) {
|
||||
super(x, y, width, height, Text.of(""));
|
||||
this.screen = screen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrices, int mouseX, int mouseY, float tickDelta) {
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
// Render the armor icon to test
|
||||
client.getTextureManager().bindTexture(InGameHud.GUI_ICONS_TEXTURE);
|
||||
DrawableHelper.drawTexture(matrices, this.x, this.y, this.width, this.height, 43, 27, 9, 9, 256, 256);
|
||||
|
||||
if (this.isMouseOver(mouseX, mouseY)) {
|
||||
this.screen.renderTooltip(matrices, new LiteralText("Click to stop all sounds"), this.x, this.y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPress() {
|
||||
MinecraftClient.getInstance().getSoundManager().stopAll();
|
||||
}
|
||||
}
|
16
fabric-screen-api-v1/src/testmod/resources/fabric.mod.json
Normal file
16
fabric-screen-api-v1/src/testmod/resources/fabric.mod.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-screen-api-v1-testmod",
|
||||
"name": "Fabric Screen API (v1) Test Mod",
|
||||
"version": "1.0.0",
|
||||
"environment": "client",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-screen-api-v1": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.screen.ScreenTests"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -49,6 +49,7 @@ include 'fabric-rendering-v1'
|
|||
include 'fabric-rendering-data-attachment-v1'
|
||||
include 'fabric-rendering-fluids-v1'
|
||||
include 'fabric-resource-loader-v0'
|
||||
include 'fabric-screen-api-v1'
|
||||
include 'fabric-screen-handler-api-v1'
|
||||
include 'fabric-structure-api-v1'
|
||||
include 'fabric-tag-extensions-v0'
|
||||
|
|
Loading…
Reference in a new issue