-
Notifications
You must be signed in to change notification settings - Fork 49
Creating custom widgets
Sometimes you need a widget that isn't available out of the box. You can use custom widget types to create customized versions of stock widgets or completely new ones.
If you want to create a completely new widget, you can extend the WWidget
class. If, however you only need to change a specific method, you should extend the widget that comes closest to what you want and override what's necessary.
Below is a basic widget class skeleton.
public class WMyWidget extends WWidget {
@Override
public boolean canResize() {
return true; // set to false if you want a static size
}
@Environment(EnvType.CLIENT)
@Override
public void paint(DrawContext context, int x, int y, int mouseX, int mouseY) {
// This is the most important method of a custom widget, where you decide how it'll look.
}
}
To that skeleton, you can add painting code and input handlers.
The main utility class is ScreenDrawing
, which can be used to draw various shapes and images on the screen.
public class WMyWidget extends WWidget {
private static final Identifier TEXTURE = Identifier.of("mymod", "textures/gui/my_widget.png");
// ...
@Environment(EnvType.CLIENT)
@Override
public void paint(DrawContext context, int x, int y, int mouseX, int mouseY) {
// If you want the whole texture
ScreenDrawing.texturedRect(context, x, y, width, height, TEXTURE, 0xFFFFFFFF);
// or for partial textures:
ScreenDrawing.texturedRect(context, x, y, width, height, TEXTURE, u1, v1, u2, v2, 0xFFFFFFFF);
// u1, v1, u2, v2 are fractions of the texture dimensions, so for example for the top half (u: 0-1, v: 0-0.5):
ScreenDrawing.texturedRect(context, x, y, width, height, TEXTURE, 0f, 0f, 1f, 0.5f, 0xFFFFFFFF);
// the 0xFFFFFFFF is the color in ARGB format, which in this case is white
}
}
There are several event methods in the WWidget
class that can be overwritten to change functionality. We will go over a few of them.
Note that they all return InputResult
. This describes whether the mouse input was PROCESSED
or IGNORED
. It's important to return the correct value since it affects the passthrough of mouse events - by returning IGNORED
, you're allowing the ignored mouse event to pass through to lower widgets.
The obvious one. When a user clicks on WMyWidget
then onClick
will execute.
public class WMyWidget extends WWidget {
@Environment(EnvType.CLIENT)
@Override
public InputResult onClick(int x, int y, int button) {
// x & y are the coordinates of the mouse when the event was triggered
// int button is which button was pressed
return InputResult.PROCESSED;
}
}
The button
codes are:
- 0: Left mouse button
- 1: Right mouse button
- 2: Scrollwheel mouse button
This event will trigger when the user scrolls in the widget.
public class WMyWidget extends WWidget {
@Environment(EnvType.CLIENT)
@Override
public InputResult onMouseScroll(int x, int y, double amount) {
super.onMouseScroll(x, y, amount);
// x & y are the coordinates of the mouse when the event was triggered
return InputResult.PROCESSED;
}
}
amount
will be positive when you scroll up and negative when you scroll down.
Some events will only trigger when a widget has been focused (like focusing an input field). To do this we need to override the canFocus
so it returns true
. After that we need to call requestFocus
to actually focus it.
public class WMyWidget extends WWidget {
@Environment(EnvType.CLIENT)
@Override
public InputResult onClick(int x, int y, int button) {
requestFocus(); // To focus a widget
return InputResult.PROCESSED;
}
@Override
public boolean canFocus() {
return true; // To make a widget able to become focused
}
}
When a widget has gained focus, the event onFocusGained
method will trigger. When it loses focus again the onFocusLost
method will trigger.
Keyboard events will only trigger when your widget is focused.
There are two different keyboard events, onKeyPressed
and onCharTyped
.
onCharTyped
will only pass what character was typed
onKeyPressed
will pass 3 parameters:
-
ch
: The keyboard key that was pressed or released -
key
: The system-specific scancode of the key -
modifiers
: bitfield describing which modifiers keys were held down
public class WMyWidget extends WWidget {
@Environment(EnvType.CLIENT)
@Override
public InputResult onClick(int x, int y, int button) {
requestFocus();
return InputResult.PROCESSED;
}
@Override
public boolean canFocus() {
return true;
}
@Environment(EnvType.CLIENT)
@Override
public void onCharTyped(char ch) {
System.out.println("Character typed: " + ch);
}
@Environment(EnvType.CLIENT)
@Override
public void onKeyPressed(int ch, int key, int modifiers) {
System.out.println("Key pressed: " + ch);
}
}
In the code example we focus the widget by clicking on it. After we have done that the onCharTyped
and onKeyPressed
methods will be triggered.
onMouseDown(int x, int y, int button)
onMouseUp(int x, int y, int button)
onMouseDrag(int x, int y, int button, double deltaX, double deltaY)
onClick(int x, int y, int button)
onMouseScroll(int x, int y, double amount)
onMouseMove(int x, int y)
onCharTyped(char ch)
onKeyPressed(int ch, int key, int modifiers)
onKeyReleased(int ch, int key, int modifiers)
onFocusGained()
onFocusLost()