Creating a custom skin
Creating a Custom Skin
This section guides you through creating a custom Skin to define a unique context menu appearance.
Steps
- Extend - Skin:- Create a new class extending - Skin.
- Optionally implement - GroupableSkinfor option group support.
 
- Register Renderers: - In the constructor, use - addRendererto register- SkinRendererinstances for supported option types.
 
- Implement - renderContextMenu:- Draw the menu’s background and layout. 
- Iterate over - getOptionsto render each option using its renderer.
 
- Handle Input: - Override input methods ( - mouseClicked, etc.) for menu-level interactions.
- Delegate option-specific input to renderers. 
 
- Set Screen Behavior: - Use - setCreateNewScreento determine if the menu opens in a new screen.
 
Example:
public class SimpleSkin extends Skin {
    public SimpleSkin() {
        addRenderer(BooleanOption.class, SimpleBooleanRenderer::new);
        setCreateNewScreen(false); // This will open this skin in the moveable screen itself. eg: classic skin
    }
    @Override
    public void renderContextMenu(DrawContext drawContext, ContextMenu<?> contextMenu, int mouseX, int mouseY) {
        this.contextMenu = contextMenu;
        //Some padding and dimension definition
        int yOffset = contextMenu.y + 2;
        int width = 10;
        // Draw background
        DrawHelper.drawRectangle(drawContext.getMatrices().peek().getPositionMatrix(),
            contextMenu.x, contextMenu.y, 100, contextMenu.getHeight(), 0x80000000);
        // Render options
        // You MUST use getOptions(contextMenu) so you avoid problems with setting groups
        for (Option<?> option : getOptions(contextMenu)) {
            if (!option.shouldRender()) continue;
            option.render(drawContext, contextMenu.x + 2, yOffset, mouseX, mouseY);
            width = Math.max(width, option.getWidth());
            yOffset += option.getHeight() + 1;
        }
        contextMenu.setWidth(width + 4);
        contextMenu.setHeight(yOffset - contextMenu.y);
    }
    public static class SimpleBooleanRenderer implements SkinRenderer<BooleanOption> {
        @Override
        public void render(DrawContext drawContext, BooleanOption option, int x, int y, int mouseX, int mouseY) {
            option.setPosition(x, y);
            option.setHeight(10);
            option.setWidth(mc.textRenderer.getWidth(option.getName().getString()) + 10);
            int color = option.get() ? 0x00FF00 : 0xFF0000;
            drawContext.drawText(mc.textRenderer, option.getName(), x, y, color, false);
        }
    }
}Common Pitfalls
- Not Setting Dimensions: Failing to update - contextMenu.setWidthand- contextMenu.setHeightcan cause clipping.- Fix: Calculate and set dimensions based on rendered options. 
 
- Ignoring Group Support: If - supportsGroups()is false, groups are flattened, which may break hierarchical menus.- Fix: Implement - GroupableSkinif groups are needed.
 
Test your skin with all supported option types to ensure renderers are correctly registered.
Last updated
Was this helpful?
