### Accessing Sunscreen Library and Session Management Source: https://context7.com/combimagnetron/sunscreen/llms.txt Demonstrates how to get the singleton SunscreenLibrary instance, access the session handler to check if a user is in a menu, retrieve the current session, and get the plugin data path. Ensure the necessary imports are present. ```java import me.combimagnetron.sunscreen.SunscreenLibrary; import me.combimagnetron.sunscreen.neo.session.SessionHandler; import me.combimagnetron.sunscreen.user.SunscreenUser; // Get the library instance (singleton pattern) SunscreenLibrary library = SunscreenLibrary.library(); // Access session handler to manage active menus SessionHandler sessionHandler = library.sessionHandler(); // Check if a user is currently in a menu SunscreenUser user = library.users().get(player); boolean isInMenu = sessionHandler.inMenu(user); // Access the current session for a user Session currentSession = sessionHandler.session(user); if (currentSession != null) { ActiveMenu menu = currentSession.menu(); // Work with the active menu } // Get the plugin data path for resources Path dataPath = library.path(); // Load a resource from the plugin InputStream resource = library.resource("textures/button.png"); ``` -------------------------------- ### Create Scalable UI Elements with NineSlice Source: https://context7.com/combimagnetron/sunscreen/llms.txt Shows how to create scalable UI elements using the NineSlice class, which divides a canvas into 9 sections for independent scaling. Examples include creating from a source canvas and rendering at different sizes. ```java import me.combimagnetron.passport.util.math.Vec2i; import me.combimagnetron.sunscreen.neo.graphic.Canvas; import me.combimagnetron.sunscreen.neo.graphic.NineSlice; // Create a nine-slice from a 9x9 source canvas (equal divisions) Canvas source = Canvas.resource("button_9slice.png"); // Should be 9x9 or larger NineSlice nineSlice = NineSlice.nineSlice(source); // Render at different sizes Canvas smallButton = nineSlice.size(Vec2i.of(80, 24)); Canvas largeButton = nineSlice.size(Vec2i.of(200, 40)); Canvas wideButton = nineSlice.size(Vec2i.of(300, 30)); // Create nine-slice with custom corner sizes Canvas customSource = Canvas.resource("panel.png"); NineSlice customSlice = NineSlice.nineSlice( customSource, Vec2i.of(8, 8), // Top-left corner size Vec2i.of(8, 8), // Top edge height, bottom corner width Vec2i.of(8, 8) // Left edge width, middle height ); Canvas scaledPanel = customSlice.size(Vec2i.of(400, 300)); // Access individual slice parts Canvas[] parts = nineSlice.parts(); // Array of 9 canvas pieces // Index: 0=top-left, 1=top, 2=top-right, 3=left, 4=center, 5=right, 6=bottom-left, 7=bottom, 8=bottom-right ``` -------------------------------- ### Configure Fixed, Fit, Relative, and Responsive Sizes Source: https://context7.com/combimagnetron/sunscreen/llms.txt Illustrates creating Size objects for absolute pixel dimensions, automatic content fitting, percentage-based relative sizing, and combined percentage and pixel adjustments for responsive design. Also shows applying a Size to an element. ```java import me.combimagnetron.passport.util.math.Vec2i; import me.combimagnetron.sunscreen.neo.property.Size; import me.combimagnetron.sunscreen.neo.property.RelativeMeasure; // Fixed size (absolute pixel dimensions) Size fixed = Size.fixed(Vec2i.of(200, 100)); // Fit to content size (automatic) Size fitContent = Size.fit(); // Relative sizing using percentages Size halfWidth = Size.relative( RelativeMeasure.vec2i() .x().percentage(50).back() // 50% of parent width .y().percentage(100).back() // 100% of parent height ); // Combined percentage and pixel adjustment Size responsive = Size.relative( RelativeMeasure.vec2i() .x().percentage(100).pixel(-40).back() // Full width minus 40px margin .y().percentage(50).pixel(0).back() // Half height ); // Apply size to element Elements.image(Identifier.of("myplugin", "banner"), Canvas.resource("banner.png")) .position(Position.fixed(Vec2i.of(0, 0))) .size(Size.relative( RelativeMeasure.vec2i() .x().percentage(100).back() .y().percentage(20).back() )); ``` -------------------------------- ### Configure Fixed, Nil, Relative, and Dynamic Positions Source: https://context7.com/combimagnetron/sunscreen/llms.txt Demonstrates creating Position objects for absolute pixel coordinates, zero position, percentage-based relative positioning with pixel adjustments, and dynamic positioning using a supplier. Also shows how to build a RelativeMeasure for complex positioning and apply a Position to an element. ```java import me.combimagnetron.passport.util.math.Vec2i; import me.combimagnetron.sunscreen.neo.property.Position; import me.combimagnetron.sunscreen.neo.property.RelativeMeasure; // Fixed position (absolute pixel coordinates) Position fixed = Position.fixed(Vec2i.of(100, 50)); // Nil/zero position Position origin = Position.nil(); // Relative positioning using percentages Position centered = Position.relative( RelativeMeasure.vec2i() .x().percentage(50).pixel(-50).back() // 50% - 50px (center 100px element) .y().percentage(50).pixel(-25).back() // 50% - 25px (center 50px element) ); // Position with supplier for dynamic values Position dynamic = Position.supplied(() -> { // Calculate position based on runtime conditions return Vec2i.of(calculateX(), calculateY()); }); // Relative measure building RelativeMeasure.Vec2iRelativeMeasureGroup measure = RelativeMeasure.vec2i() .x() .percentage(25) // 25% from left .pixel(10) // Plus 10 pixels .back() .y() .percentage(100) // 100% (bottom) .pixel(-40) // Minus 40 pixels .back(); Position bottomLeft = Position.relative(measure); // Apply position to element Elements.button(Identifier.of("myplugin", "btn")) .position(Position.fixed(Vec2i.of(200, 100))) .size(Size.fixed(Vec2i.of(80, 30))); ``` -------------------------------- ### Create and Style Text with Sunscreen Neo Source: https://context7.com/combimagnetron/sunscreen/llms.txt Demonstrates various ways to create and style text using the Text interface, including basic text, Adventure component conversion, custom fonts, and reactive text. ```java import me.combimagnetron.passport.logic.state.State; import me.combimagnetron.sunscreen.neo.graphic.text.Text; import me.combimagnetron.sunscreen.neo.graphic.text.style.impl.color.TextColor; import me.combimagnetron.sunscreen.neo.graphic.text.style.impl.font.Font; import me.combimagnetron.sunscreen.neo.graphic.text.style.impl.font.FontProperties; import me.combimagnetron.sunscreen.neo.registry.Registries; import net.kyori.adventure.text.Component; // Create basic text Text simple = Text.basic("Hello, World!"); // Create text from Adventure component (preserves styling) Text adventureText = Text.adventure( Component.text("Styled ") .append(Component.text("Text").color(NamedTextColor.GOLD)) ); // Apply text styling Text styled = Text.basic("Styled Text") .color(TextColor.color(Color.of(255, 200, 0))) .fontProperties(FontProperties.properties().baseline(-6)); // Use custom fonts Font minecraftFont = Registries.fonts().get(Identifier.of("sunscreen", "font/minecraft")); Text customFont = Text.basic("Custom Font") .font(minecraftFont) .fontProperties(FontProperties.properties().baseline(-4)); // Chain multiple text segments Text chained = Text.chained( Text.basic("Part 1 ").color(TextColor.color(Color.of(255, 0, 0))), Text.basic("Part 2 ").color(TextColor.color(Color.of(0, 255, 0))), Text.basic("Part 3").color(TextColor.color(Color.of(0, 0, 255))) ); // Reactive text that updates automatically State dynamicValue = State.mutable("Initial Value"); Text reactive = Text.state(dynamicValue); // When dynamicValue changes, the text automatically updates // Append text Text appended = Text.basic("Hello, ") .append(Text.basic("World!")); // Display keybind text Text keybindText = Text.keybind(Keybind.of(Keybind.NamedKey.E, Keybind.NamedModifier.SHIFT)); ``` -------------------------------- ### Configure ButtonElement with event listeners Source: https://context7.com/combimagnetron/sunscreen/llms.txt Demonstrates creating buttons with custom canvases or text, and attaching click event listeners using the fluent API. ```java import me.combimagnetron.sunscreen.neo.element.impl.ButtonElement; import me.combimagnetron.sunscreen.neo.event.UserClickElementEvent; import me.combimagnetron.sunscreen.neo.graphic.Canvas; import me.combimagnetron.sunscreen.neo.graphic.text.Text; // Create a button with click listener ButtonElement closeButton = Elements.button(Identifier.of("myplugin", "close")) .position(Position.fixed(Vec2i.of(350, 10))) .size(Size.fixed(Vec2i.of(40, 40))); // Add click event listener using the fluent API closeButton.listen() .click(event -> { // event.user() - the user who clicked // event.element() - the button element // event.coords() - click position relative to the button SunscreenUser user = event.user(); Vec2i clickPosition = event.coords(); // Close the menu when button is clicked library.sessionHandler().session(user).menu().close(); }) .back(); // Return to the element for chaining // Set a custom canvas for the button appearance ButtonElement customButton = Elements.button(Identifier.of("myplugin", "custom")) .canvas(Canvas.resource("custom_button.png")) .position(Position.fixed(Vec2i.of(100, 100))) .size(Size.fixed(Vec2i.of(80, 30))); // Button with text and custom positioning ButtonElement textButton = new ButtonElement( Identifier.of("myplugin", "action"), Text.basic("Click Me").color(TextColor.color(Color.of(255, 255, 255))), Vec2i.of(15, 8) // Text position offset ).position(Position.fixed(Vec2i.of(200, 200))) .size(Size.fixed(Vec2i.of(100, 32))); ``` -------------------------------- ### Implement TextFieldElement input handling Source: https://context7.com/combimagnetron/sunscreen/llms.txt Shows how to create text input fields with configurable clearing behavior and subscribe to input events via the EventBus. ```java import me.combimagnetron.sunscreen.neo.element.impl.text.TextFieldElement; import me.combimagnetron.sunscreen.neo.event.UserFinishTextInputEvent; import me.combimagnetron.sunscreen.neo.event.UserUpdateTextInputEvent; // Create a text input field TextFieldElement usernameField = Elements.textField(Identifier.of("myplugin", "username")) .position(Position.fixed(Vec2i.of(100, 100))) .size(Size.fixed(Vec2i.of(200, 20))) .shouldClear(true); // Clear text when clicking (default behavior) // Create a text field that preserves existing text when clicked TextFieldElement searchField = Elements.textField(Identifier.of("myplugin", "search")) .position(Position.fixed(Vec2i.of(100, 140))) .size(Size.fixed(Vec2i.of(250, 20))) .shouldClear(false); // Preserve text when re-focusing // Add to menu root root.element(usernameField); root.element(searchField); // Listen for text input changes (subscribe via EventBus) EventBus.subscribe(UserUpdateTextInputEvent.class, event -> { String currentText = event.context().stream().value(); // Handle real-time text updates System.out.println("User typing: " + currentText); }); // Listen for completed text input EventBus.subscribe(UserFinishTextInputEvent.class, event -> { String finalText = event.context().stream().value(); // Handle submitted text System.out.println("User submitted: " + finalText); }); ``` -------------------------------- ### Initialize SliderElement for numeric input Source: https://context7.com/combimagnetron/sunscreen/llms.txt Demonstrates basic initialization of a slider element and its addition to the menu root. ```java import me.combimagnetron.sunscreen.neo.element.impl.SliderElement; // Create a slider element SliderElement volumeSlider = new SliderElement(Identifier.of("myplugin", "volume")) .position(Position.fixed(Vec2i.of(100, 200))); // Slider automatically handles: // - Mouse drag for value changes // - Visual feedback with cursor change to resize_horizontal // - Value display (0-100 range by default) // Add to menu root root.element(volumeSlider); ``` -------------------------------- ### Defining a Custom Menu Template in Sunscreen Source: https://context7.com/combimagnetron/sunscreen/llms.txt Shows how to implement the MenuTemplate interface to define a custom menu structure. This includes setting a unique identifier and building the menu's content by adding themes and UI elements. ```java import me.combimagnetron.passport.util.data.Identifier; import me.combimagnetron.sunscreen.neo.MenuRoot; import me.combimagnetron.sunscreen.neo.MenuTemplate; import org.jetbrains.annotations.NotNull; public class MyCustomMenuTemplate implements MenuTemplate { private static final Identifier IDENTIFIER = Identifier.of("myplugin", "main_menu"); @Override public @NotNull Identifier identifier() { return IDENTIFIER; } @Override public void build(@NotNull MenuRoot root) { // Add theme configuration root.theme( ModernTheme.theme(Identifier.of("myplugin", "main_menu/theme")) .colorScheme(ColorSchemes.BASIC_DARK) ); // Add elements to the menu root.element( Elements.button(Identifier.of("myplugin", "close_button")) .position(Position.fixed(Vec2i.of(100, 50))) .size(Size.fixed(Vec2i.of(80, 24))) ); root.element( Elements.label( Identifier.of("myplugin", "title"), Text.basic("Welcome to My Menu") ).position(Position.fixed(Vec2i.of(200, 20))) ); } } ``` -------------------------------- ### Configure ModernTheme with Decorators Source: https://context7.com/combimagnetron/sunscreen/llms.txt Create a custom theme using ModernTheme, applying color schemes and state-aware or nine-slice decorators to elements. Elements can be targeted by type or identifier. ```java import me.combimagnetron.passport.util.data.Identifier; import me.combimagnetron.sunscreen.neo.graphic.Canvas; import me.combimagnetron.sunscreen.neo.graphic.NineSlice; import me.combimagnetron.sunscreen.neo.theme.ModernTheme; import me.combimagnetron.sunscreen.neo.theme.color.ColorSchemes; import me.combimagnetron.sunscreen.neo.theme.decorator.Target; import me.combimagnetron.sunscreen.neo.theme.decorator.ThemeDecorator; // Create a theme with color scheme and decorators ModernTheme theme = ModernTheme.theme(Identifier.of("myplugin", "dark_theme")) .colorScheme(ColorSchemes.BASIC_DARK) // Add state-aware decorator for buttons (changes appearance on hover/click) .decorator( ThemeDecorator.stated(Target.typed(ButtonElement.class)) .standard(Canvas.resource("button_default.png")) .hovered(Canvas.resource("button_hover.png")) .clicked(Canvas.resource("button_click.png")) ) // Add nine-slice decorator for text fields (scalable borders) .decorator( ThemeDecorator.nineSlice( Target.typed(TextFieldElement.class), NineSlice.nineSlice( Canvas.empty(Vec2i.of(9, 9)) .fill(Vec2i.zero(), Vec2i.of(9, 9), Color.of(40, 40, 40)) ) ) ) // Target specific element by identifier for custom styling .decorator( ThemeDecorator.stated( Target.identifier(Identifier.of("myplugin", "decorator/primary_button")) ) .standard(Canvas.resource("primary_default.png")) .hovered(Canvas.resource("primary_hover.png")) .clicked(Canvas.resource("primary_click.png")) ); ``` ```java // Apply theme to menu root @Override public void build(@NotNull MenuRoot root) { root.theme(theme); // Elements will automatically use theme decorators root.element( Elements.button(Identifier.of("myplugin", "themed_button")) .position(Position.fixed(Vec2i.of(100, 100))) .size(Size.fixed(Vec2i.of(100, 30))) ); // Use specific decorator via identifier root.element( Elements.button(Identifier.of("myplugin", "primary_action")) .position(Position.fixed(Vec2i.of(100, 150))) .size(Size.fixed(Vec2i.of(120, 36))) .decorator(Decorator.decorator( Target.identifier(Identifier.of("myplugin", "decorator/primary_button")) )) ); } ``` -------------------------------- ### Registering Keyboard Shortcuts with Keybind Source: https://context7.com/combimagnetron/sunscreen/llms.txt Use the Keybind class to register keyboard shortcuts, including modifier keys like Shift and Ctrl. Listeners can be attached to handle key presses. Keybinds are registered with the menu. ```java import me.combimagnetron.sunscreen.neo.input.keybind.Keybind; import me.combimagnetron.sunscreen.neo.event.UserPressKeybindEvent; // Create keybind for Escape (E key / inventory) Keybind closeKeybind = Keybind.of(Keybind.NamedKey.E); // Create keybind with modifiers (Shift + E) Keybind saveKeybind = Keybind.of( Keybind.NamedKey.E, Keybind.NamedModifier.SHIFT ); // Create keybind with multiple modifiers (Ctrl + Shift + S) Keybind quickSave = Keybind.of( Keybind.Registered.FORWARD, // W key Keybind.NamedModifier.CTRL, Keybind.NamedModifier.SHIFT ); // Add keybind listener closeKeybind.listen() .pressed(event -> { // Handle keybind press SunscreenUser user = event.user(); library.sessionHandler().session(user).menu().close(); }) .back(); // Register keybind with menu @Override public void build(@NotNull MenuRoot root) { root.keybind(closeKeybind); root.keybind(saveKeybind); // Other menu elements... } ``` ```java // Available named keys (mapped to Minecraft bindings) // W, S, A, D - Movement keys // Q - Drop item // E - Inventory // F - Swap hand // L - Advancements // KEY_1 through KEY_9 - Hotbar slots // Available modifiers // CTRL (Sprint key) // SHIFT (Sneak key) // SPACE (Jump key) ``` -------------------------------- ### SunscreenLibrary Interface Source: https://context7.com/combimagnetron/sunscreen/llms.txt The central access point for managing sessions, user states, and resource loading within the Sunscreen library. ```APIDOC ## SunscreenLibrary Interface ### Description The `SunscreenLibrary` interface is the singleton entry point for the library, providing access to session management, user tracking, and resource handling. ### Methods - **library()**: Returns the singleton instance of the library. - **sessionHandler()**: Returns the `SessionHandler` for managing active menus. - **users()**: Returns the user manager to retrieve `SunscreenUser` instances. - **resource(String path)**: Loads a resource from the plugin's data path. ### Usage Example ```java SunscreenLibrary library = SunscreenLibrary.library(); SessionHandler sessionHandler = library.sessionHandler(); SunscreenUser user = library.users().get(player); ``` ``` -------------------------------- ### Create Flow and Group Layouts Source: https://context7.com/combimagnetron/sunscreen/llms.txt Utilize Layout.flow for automatic element wrapping and Layout.group for absolute positioning within a container. Elements can be added or removed dynamically. ```java import me.combimagnetron.passport.util.data.Identifier; import me.combimagnetron.sunscreen.neo.layout.Layout; // Create a flow layout (elements wrap to next row when full) Layout flowLayout = Layout.flow( Identifier.of("myplugin", "button_row"), Elements.button(Identifier.of("myplugin", "btn1")) .size(Size.fixed(Vec2i.of(60, 30))), Elements.button(Identifier.of("myplugin", "btn2")) .size(Size.fixed(Vec2i.of(60, 30))), Elements.button(Identifier.of("myplugin", "btn3")) .size(Size.fixed(Vec2i.of(60, 30))) ).position(Position.fixed(Vec2i.of(50, 100))) .size(Size.fixed(Vec2i.of(200, 100))); // Elements wrap within this area // Create a group layout (elements positioned relative to group origin) Layout groupLayout = Layout.group( Identifier.of("myplugin", "dialog_box"), Elements.image( Identifier.of("myplugin", "dialog_bg"), Canvas.resource("dialog_background.png") ).position(Position.fixed(Vec2i.of(0, 0))), Elements.label( Identifier.of("myplugin", "dialog_title"), Text.basic("Confirm Action") ).position(Position.fixed(Vec2i.of(20, 10))), Elements.button(Identifier.of("myplugin", "dialog_yes")) .position(Position.fixed(Vec2i.of(20, 60))) .size(Size.fixed(Vec2i.of(60, 24))), Elements.button(Identifier.of("myplugin", "dialog_no")) .position(Position.fixed(Vec2i.of(100, 60))) .size(Size.fixed(Vec2i.of(60, 24))) ).position(Position.fixed(Vec2i.of(200, 150))) .size(Size.fixed(Vec2i.of(180, 100))); ``` ```java // Add elements dynamically to layout flowLayout.add( Elements.button(Identifier.of("myplugin", "btn4")) .size(Size.fixed(Vec2i.of(60, 30))) ); // Remove element from layout groupLayout.remove(Identifier.of("myplugin", "dialog_title")); // Add layout to menu root root.element(flowLayout); root.element(groupLayout); ``` -------------------------------- ### Color Definition and Conversion Source: https://context7.com/combimagnetron/sunscreen/llms.txt The Color interface supports RGB, RGBA, hex strings, and integration with Kyori Adventure TextColor. ```java import me.combimagnetron.sunscreen.neo.graphic.color.Color; import net.kyori.adventure.text.format.TextColor; // Create color from RGB values (0-255) Color red = Color.of(255, 0, 0); Color green = Color.of(0, 255, 0); Color blue = Color.of(0, 0, 255); // Create color with alpha transparency Color semiTransparent = Color.of(255, 255, 255, 128); // 50% opacity white Color fullyOpaque = Color.of(100, 100, 100, 255); // Create color from hex string Color hexColor = Color.hex("#FF5733"); // 6-digit RGB hex Color hexWithAlpha = Color.hex("80FF5733"); // 8-digit ARGB hex // Create from packed integer Color packedRgb = Color.of(0xFF5733); Color packedRgba = Color.rgba(0x80FF5733); // Convert from Adventure TextColor TextColor adventureColor = TextColor.color(0x00FFAA); Color fromAdventure = Color.of(adventureColor); // Special color values Color transparent = Color.none(); // Fully transparent ``` -------------------------------- ### Create UI elements with Elements factory Source: https://context7.com/combimagnetron/sunscreen/llms.txt The Elements interface provides a fluent builder pattern for creating buttons, labels, text inputs, images, and shapes. Each element requires a unique Identifier. ```java import me.combimagnetron.passport.util.data.Identifier; import me.combimagnetron.passport.util.math.Vec2i; import me.combimagnetron.sunscreen.neo.element.Elements; import me.combimagnetron.sunscreen.neo.graphic.Canvas; import me.combimagnetron.sunscreen.neo.graphic.color.Color; import me.combimagnetron.sunscreen.neo.graphic.shape.Shape; import me.combimagnetron.sunscreen.neo.graphic.text.Text; import me.combimagnetron.sunscreen.neo.property.Position; import me.combimagnetron.sunscreen.neo.property.Size; // Create a button element ButtonElement button = Elements.button(Identifier.of("myplugin", "submit_button")) .position(Position.fixed(Vec2i.of(100, 200))) .size(Size.fixed(Vec2i.of(120, 32))); // Create a button with text label ButtonElement labeledButton = Elements.button( Identifier.of("myplugin", "confirm_button"), Text.basic("Confirm"), Vec2i.of(10, 8) // Text offset within button ).position(Position.fixed(Vec2i.of(100, 250))) .size(Size.fixed(Vec2i.of(100, 30))); // Create a label element with Adventure component LabelElement label = Elements.label( Identifier.of("myplugin", "status_label"), Component.text("Status: Ready").color(NamedTextColor.GREEN) ).position(Position.fixed(Vec2i.of(50, 50))); // Create a text input field TextFieldElement textField = Elements.textField(Identifier.of("myplugin", "name_input")) .position(Position.fixed(Vec2i.of(100, 150))) .size(Size.fixed(Vec2i.of(200, 20))); // Create a multi-line text editor TextEditorElement textEditor = Elements.textEditor(Identifier.of("myplugin", "description")) .position(Position.fixed(Vec2i.of(100, 180))) .size(Size.fixed(Vec2i.of(300, 100))); // Create an image element from various sources ImageElement imageFromFile = Elements.image( Identifier.of("myplugin", "logo"), Canvas.resource("logo.png") // From plugin resources ).position(Position.fixed(Vec2i.of(10, 10))); ImageElement imageFromUrl = Elements.image( Identifier.of("myplugin", "avatar"), Canvas.url("https://example.com/avatar.png") ).position(Position.fixed(Vec2i.of(50, 50))); // Create shape elements ShapeElement rectangle = Elements.shape( Identifier.of("myplugin", "border"), Shape.rectangle(Vec2i.of(100, 50)), Color.of(255, 255, 255) ).position(Position.fixed(Vec2i.of(200, 100))); ShapeElement circle = Elements.shape( Identifier.of("myplugin", "indicator"), Shape.circle(20), Color.of(0, 255, 0) ).position(Position.fixed(Vec2i.of(300, 150))); ShapeElement line = Elements.shape( Identifier.of("myplugin", "divider"), Shape.line(Vec2i.of(0, 0), Vec2i.of(200, 0), 2), Color.of(128, 128, 128) ).position(Position.fixed(Vec2i.of(100, 200))); ``` -------------------------------- ### Managing Input State with InputHandler Source: https://context7.com/combimagnetron/sunscreen/llms.txt The InputHandler class manages input contexts for mouse, scroll, and text. Subscribe to events for real-time input or retrieve the current state of input contexts. Input contexts can also be programmatically updated. ```java import me.combimagnetron.sunscreen.neo.input.InputHandler; import me.combimagnetron.sunscreen.neo.input.context.MouseInputContext; import me.combimagnetron.sunscreen.neo.input.context.ScrollInputContext; import me.combimagnetron.sunscreen.neo.input.context.TextInputContext; import me.combimagnetron.sunscreen.neo.event.UserMoveStateChangeEvent; import me.combimagnetron.sunscreen.neo.event.UserScrollStateChangeEvent; // Get input handler from active menu InputHandler inputHandler = activeMenu.inputHandler(); // Subscribe to mouse movement/click events inputHandler.subscribe(MouseInputContext.class, (UserMoveStateChangeEvent event) -> { MouseInputContext context = event.context(); Vec2i cursorPosition = context.position(); boolean leftPressed = context.leftPressed(); boolean rightPressed = context.rightPressed(); // Handle mouse input }); // Subscribe to scroll events inputHandler.subscribe(ScrollInputContext.class, (UserScrollStateChangeEvent event) -> { ScrollInputContext context = event.context(); float scrollDelta = context.delta(); // Handle scroll input }); // Get current input context state MouseInputContext mouseState = inputHandler.context(MouseInputContext.class); Vec2i currentCursorPos = mouseState.position(); TextInputContext textState = inputHandler.context(TextInputContext.class); String currentText = textState.stream().value(); boolean isTyping = textState.active(); // Programmatically update input context inputHandler.peek(TextInputContext.class, context -> context.append("Appended text"), inputHandler.user() ); // Open anvil for text input inputHandler.anvil(true); // true = clear existing text // Change cursor style inputHandler.cursor(CursorStyle.busy()); ``` -------------------------------- ### Manage ActiveMenu lifecycle and elements Source: https://context7.com/combimagnetron/sunscreen/llms.txt Use ActiveMenu to display menus, modify elements dynamically, and update cursor styles. Ensure the menu is closed to restore player state. ```java import me.combimagnetron.passport.util.data.Identifier; import me.combimagnetron.sunscreen.neo.ActiveMenu; import me.combimagnetron.sunscreen.neo.MenuTemplate; import me.combimagnetron.sunscreen.neo.cursor.CursorStyle; import me.combimagnetron.sunscreen.user.SunscreenUser; // Open a menu for a player MenuTemplate template = new MyCustomMenuTemplate(); SunscreenUser user = library.users().get(player); ActiveMenu menu = new ActiveMenu(template, user, template.identifier()); // Dynamically add elements to an active menu menu.add( Elements.image( Identifier.of("myplugin", "notification_icon"), Canvas.resource("notification.png") ).position(Position.fixed(Vec2i.of(300, 100))) ); // Remove an element by identifier menu.remove(Identifier.of("myplugin", "notification_icon")); // Get an element from the menu ElementLike button = menu.element(Identifier.of("myplugin", "close_button")); // Change the cursor style menu.cursor(CursorStyle.click()); // Hand pointer for clickable areas menu.cursor(CursorStyle.pointer()); // Default arrow cursor menu.cursor(CursorStyle.textCaret()); // Text input cursor menu.cursor(CursorStyle.busy()); // Loading cursor // Close the menu and restore player state menu.close(); ``` -------------------------------- ### MenuTemplate Definition Source: https://context7.com/combimagnetron/sunscreen/llms.txt Defines the structure and content of a menu using the MenuTemplate interface. ```APIDOC ## MenuTemplate Interface ### Description `MenuTemplate` is used to define the layout, theme, and elements of a GUI. Implementations must provide a unique identifier and a build method. ### Methods - **identifier()**: Returns a unique `Identifier` for the menu template. - **build(MenuRoot root)**: Defines the UI elements and theme configuration for the menu. ### Usage Example ```java public class MyCustomMenuTemplate implements MenuTemplate { @Override public void build(@NotNull MenuRoot root) { root.theme(ModernTheme.theme(...)); root.element(Elements.button(...).position(...)); } } ``` ``` -------------------------------- ### Vector Shape Creation Source: https://context7.com/combimagnetron/sunscreen/llms.txt The Shape interface provides factory methods for geometric primitives and custom polygons. ```java import me.combimagnetron.passport.util.math.Vec2i; import me.combimagnetron.sunscreen.neo.graphic.shape.Shape; // Basic shapes Shape rectangle = Shape.rectangle(Vec2i.of(100, 50)); Shape circle = Shape.circle(25); // Radius of 25 pixels Shape ellipse = Shape.ellipse(40, 20); // radiusX, radiusY Shape triangle = Shape.triangle(Vec2i.of(50, 40)); // Base and height // Rounded rectangle Shape rounded = Shape.roundedRectangle(Vec2i.of(100, 40), 8); // 8px corner radius // Lines Shape simpleLine = Shape.line(Vec2i.of(0, 0), Vec2i.of(100, 50)); Shape thickLine = Shape.line(Vec2i.of(0, 0), Vec2i.of(100, 50), 3); // 3px thick // Filled line (fills area under the line) Shape filledLine = Shape.filledLine(Vec2i.of(0, 50), Vec2i.of(100, 0)); Shape filledAbove = Shape.filledLine(Vec2i.of(0, 50), Vec2i.of(100, 0), true); // Custom polygon Shape polygon = Shape.polygon( Vec2i.of(50, 0), // Top Vec2i.of(100, 40), // Right Vec2i.of(80, 100), // Bottom right Vec2i.of(20, 100), // Bottom left Vec2i.of(0, 40) // Left ); // Draw shapes on canvas Canvas canvas = Canvas.empty(Vec2i.of(200, 200)); canvas.shape(rectangle, Color.of(255, 0, 0), Vec2i.of(10, 10)); canvas.shape(circle, Color.of(0, 255, 0), Vec2i.of(150, 100)); ``` -------------------------------- ### Canvas Drawing Surface Operations Source: https://context7.com/combimagnetron/sunscreen/llms.txt The Canvas record supports loading images, drawing shapes, text rendering, and compositing. Use these methods to manipulate 2D drawing surfaces. ```java import me.combimagnetron.passport.util.math.Vec2i; import me.combimagnetron.sunscreen.neo.graphic.Canvas; import me.combimagnetron.sunscreen.neo.graphic.color.Color; import me.combimagnetron.sunscreen.neo.graphic.shape.Shape; import me.combimagnetron.sunscreen.neo.graphic.text.Text; // Create canvas from various sources Canvas fromResource = Canvas.resource("textures/background.png"); Canvas fromUrl = Canvas.url("https://example.com/image.png"); Canvas fromFile = Canvas.file(Path.of("/path/to/image.png")); Canvas fromStream = Canvas.data(inputStream); Canvas fromBufferedImage = Canvas.image(bufferedImage); // Create an empty canvas with specified size Canvas empty = Canvas.empty(Vec2i.of(200, 100)); // Fill canvas with solid color Canvas filled = Canvas.empty(Vec2i.of(100, 50)) .fill(Vec2i.zero(), Vec2i.of(100, 50), Color.of(30, 30, 30)); // Draw a shape on the canvas Canvas withCircle = Canvas.empty(Vec2i.of(100, 100)) .shape(Shape.circle(40), Color.of(255, 0, 0), Vec2i.of(50, 50)); Canvas withRectangle = Canvas.empty(Vec2i.of(200, 100)) .shape(Shape.rectangle(Vec2i.of(180, 80)), Color.of(0, 0, 255), Vec2i.of(10, 10)); // Add text to canvas Canvas withText = Canvas.empty(Vec2i.of(200, 50)) .fill(Vec2i.zero(), Vec2i.of(200, 50), Color.of(50, 50, 50)) .text(Text.basic("Hello World"), Vec2i.of(10, 15)); // Composite multiple canvases Canvas background = Canvas.resource("background.png"); Canvas icon = Canvas.resource("icon.png"); Canvas composite = background.place(icon, Vec2i.of(10, 10)); // Scale a canvas Canvas scaled = Canvas.resource("large_image.png").scale(0.5f); // Extract a sub-region from a canvas Canvas subRegion = Canvas.resource("spritesheet.png") .sub(Vec2i.of(0, 0), Vec2i.of(32, 32)); // Extract 32x32 sprite // Replace colors in a canvas Canvas recolored = Canvas.resource("template.png") .replace(Color.of(255, 0, 0), Color.of(0, 255, 0)); // Red to green // Get canvas dimensions Vec2i size = canvas.size(); int width = size.x(); int height = size.y(); ``` -------------------------------- ### Defining Custom Cursor Styles Source: https://context7.com/combimagnetron/sunscreen/llms.txt The CursorStyle record allows using predefined cursor styles or creating custom ones using an asset identifier. Cursors can be set on the active menu and are often changed automatically by interactable elements. ```java import me.combimagnetron.passport.util.data.Identifier; import me.combimagnetron.sunscreen.neo.cursor.CursorStyle; // Use predefined cursor styles CursorStyle pointer = CursorStyle.pointer(); // Default arrow CursorStyle click = CursorStyle.click(); // Hand pointer CursorStyle textCaret = CursorStyle.textCaret(); // Text input caret CursorStyle move = CursorStyle.move(); // Move/drag cursor CursorStyle resizeH = CursorStyle.resizeHorizontal(); // Horizontal resize CursorStyle resizeV = CursorStyle.resizeVertical(); // Vertical resize CursorStyle magnify = CursorStyle.magnify(); // Zoom/magnify cursor CursorStyle busy = CursorStyle.busy(); // Loading/busy cursor // Create a custom cursor style CursorStyle customCursor = CursorStyle.style( Identifier.of("myplugin", "cursor/crosshair"), "crosshair" // Asset identifier for the cursor texture ); // Set cursor on active menu activeMenu.cursor(CursorStyle.click()); // Cursor is automatically changed by interactable elements // - Buttons change to click() on hover // - Text fields change to textCaret() when focused // - Sliders change to resizeHorizontal() when dragging ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.