CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-badlogicgames-gdx--gdx-backend-gwt

GWT backend for libGDX enabling Java game development for web browsers through JavaScript compilation

Pending
Overview
Eval results
Files

widgets.mddocs/

UI Widgets

The GWT backend provides web-specific UI components designed for browser integration and responsive behavior. These widgets handle common web deployment needs like progress indication, text input dialogs, and responsive layout management.

Core Widget Interfaces

ResizableWidget { .api }

public interface ResizableWidget {
    void resize(int width, int height);
}

ResizableWidgetCollection { .api }

public class ResizableWidgetCollection implements ResizeHandler, Iterable<ResizableWidget> {
    // Widget management
    public void add(ResizableWidget widget);
    public boolean remove(ResizableWidget widget);
    public void clear();
    public int size();
    
    // Resize handling
    public void onResize(ResizeEvent event);
    
    // Iteration support
    public Iterator<ResizableWidget> iterator();
    
    // Manual resize trigger
    public void resize(int width, int height);
}

Progress Display Widgets

ProgressBar { .api }

public class ProgressBar extends Widget implements ResizableWidget {
    // Progress control
    public void setValue(float value); // 0.0 to 1.0
    public float getValue();
    
    // Appearance
    public void setVisible(boolean visible);
    public boolean isVisible();
    public void setAnimated(boolean animated);
    public boolean isAnimated();
    
    // Styling
    public void setProgressColor(String color);
    public void setBackgroundColor(String color);
    public void setBorderColor(String color);
    public void setHeight(int height);
    
    // Text display
    public void setShowText(boolean showText);
    public boolean isShowText();
    public void setTextFormat(String format); // e.g., "{0}%" for percentage
    
    // ResizableWidget implementation
    public void resize(int width, int height);
    
    // Widget positioning
    public void setPosition(int x, int y);
    public void setSize(int width, int height);
    
    // Constructors
    public ProgressBar();
    public ProgressBar(int width, int height);
}

Text Input Widgets

TextInputDialogBox { .api }

public class TextInputDialogBox extends DialogBox {
    // Dialog display
    public void show(String title, String text, TextInputListener listener);
    public void show(String title, String text, String hint, TextInputListener listener);
    public void hide();
    
    // Dialog configuration
    public void setModal(boolean modal);
    public boolean isModal();
    public void setAnimationEnabled(boolean enabled);
    public boolean isAnimationEnabled();
    
    // Input validation
    public void setValidator(InputValidator validator);
    public InputValidator getValidator();
    public void setMaxLength(int maxLength);
    public int getMaxLength();
    
    // Styling
    public void setDialogStyle(String styleName);
    public void setButtonText(String okText, String cancelText);
    
    // Event handling
    public interface TextInputListener {
        void input(String text);
        void canceled();
    }
    
    public interface InputValidator {
        boolean isValid(String input);
        String getErrorMessage();
    }
    
    // Constructors
    public TextInputDialogBox();
    public TextInputDialogBox(boolean autoHide);
}

PlaceholderTextBox { .api }

public class PlaceholderTextBox extends TextBox {
    // Placeholder functionality
    public void setPlaceholder(String placeholder);
    public String getPlaceholder();
    
    // Enhanced text input
    public void selectAll();
    public void setSelectionRange(int start, int length);
    public String getSelectedText();
    
    // Input filtering
    public void setInputFilter(InputFilter filter);
    public InputFilter getInputFilter();
    
    // Event handling
    public void addValueChangeHandler(ValueChangeHandler<String> handler);
    public void addKeyUpHandler(KeyUpHandler handler);
    public void addFocusHandler(FocusHandler handler);
    public void addBlurHandler(BlurHandler handler);
    
    // Styling enhancements
    public void setErrorStyle(boolean error);
    public boolean hasErrorStyle();
    
    public interface InputFilter {
        boolean accept(char character);
        String filter(String input);
    }
    
    // Constructors
    public PlaceholderTextBox();
    public PlaceholderTextBox(String placeholder);
}

Usage Examples

Loading Screen with Progress Bar

public class LoadingScreen implements Screen {
    private ProgressBar progressBar;
    private ResizableWidgetCollection widgets;
    private Stage stage;
    private Label statusLabel;
    
    public LoadingScreen() {
        stage = new Stage();
        widgets = new ResizableWidgetCollection();
        
        // Create progress bar
        progressBar = new ProgressBar(400, 30);
        progressBar.setProgressColor("#00ff00");
        progressBar.setBackgroundColor("#333333");
        progressBar.setBorderColor("#666666");
        progressBar.setShowText(true);
        progressBar.setTextFormat("{0}%");
        progressBar.setAnimated(true);
        
        // Add to widget collection for automatic resizing
        widgets.add(progressBar);
        
        // Create status label
        statusLabel = new Label("Loading...", new Label.LabelStyle());
        
        // Position widgets
        layoutWidgets();
        
        // Handle window resize
        Gdx.graphics.setResizeCallback(new Graphics.ResizeCallback() {
            @Override
            public void onResize(int width, int height) {
                widgets.resize(width, height);
                layoutWidgets();
            }
        });
    }
    
    @Override
    public void show() {
        Gdx.input.setInputProcessor(stage);
    }
    
    @Override
    public void render(float delta) {
        // Update progress (example: based on asset loading)
        updateProgress();
        
        // Clear screen
        Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        
        // Render UI
        stage.act(delta);
        stage.draw();
    }
    
    private void updateProgress() {
        // Example: Update based on preloader state
        if (MyGame.getPreloader() != null) {
            Preloader.PreloaderState state = MyGame.getPreloader().update();
            float progress = state.getProgress();
            
            progressBar.setValue(progress);
            
            // Update status text
            if (progress < 0.3f) {
                statusLabel.setText("Loading graphics...");
            } else if (progress < 0.6f) {
                statusLabel.setText("Loading audio...");
            } else if (progress < 0.9f) {
                statusLabel.setText("Loading data...");
            } else if (progress < 1.0f) {
                statusLabel.setText("Finalizing...");
            } else {
                statusLabel.setText("Complete!");
            }
        }
    }
    
    private void layoutWidgets() {
        int screenWidth = Gdx.graphics.getWidth();
        int screenHeight = Gdx.graphics.getHeight();
        
        // Center progress bar
        int barX = (screenWidth - 400) / 2;
        int barY = (screenHeight - 30) / 2;
        progressBar.setPosition(barX, barY);
        
        // Position status label above progress bar
        statusLabel.setPosition(barX, barY + 50);
    }
    
    // ... other Screen methods
}

Text Input Dialog System

public class TextInputManager {
    private TextInputDialogBox currentDialog;
    
    public void showNameInput(TextInputListener listener) {
        if (currentDialog != null) {
            currentDialog.hide();
        }
        
        currentDialog = new TextInputDialogBox();
        currentDialog.setModal(true);
        currentDialog.setAnimationEnabled(true);
        currentDialog.setButtonText("OK", "Cancel");
        
        // Set up validation
        currentDialog.setValidator(new TextInputDialogBox.InputValidator() {
            @Override
            public boolean isValid(String input) {
                return input != null && input.trim().length() >= 2 && input.length() <= 20;
            }
            
            @Override
            public String getErrorMessage() {
                return "Name must be 2-20 characters long";
            }
        });
        
        currentDialog.show("Enter Your Name", "", "Your name here", new TextInputDialogBox.TextInputListener() {
            @Override
            public void input(String text) {
                currentDialog = null;
                if (listener != null) {
                    listener.input(text.trim());
                }
            }
            
            @Override
            public void canceled() {
                currentDialog = null;
                if (listener != null) {
                    listener.canceled();
                }
            }
        });
    }
    
    public void showScoreInput(int currentHighScore, TextInputListener listener) {
        if (currentDialog != null) {
            currentDialog.hide();
        }
        
        currentDialog = new TextInputDialogBox();
        currentDialog.setMaxLength(10);
        
        // Numeric validation
        currentDialog.setValidator(new TextInputDialogBox.InputValidator() {
            @Override
            public boolean isValid(String input) {
                try {
                    int score = Integer.parseInt(input);
                    return score > currentHighScore;
                } catch (NumberFormatException e) {
                    return false;
                }
            }
            
            @Override
            public String getErrorMessage() {
                return "Enter a score higher than " + currentHighScore;
            }
        });
        
        currentDialog.show("New High Score!", "", "Enter score", listener);
    }
    
    public void showCustomDialog(String title, String defaultText, String hint, 
                                TextInputDialogBox.InputValidator validator, 
                                TextInputListener listener) {
        if (currentDialog != null) {
            currentDialog.hide();
        }
        
        currentDialog = new TextInputDialogBox();
        if (validator != null) {
            currentDialog.setValidator(validator);
        }
        
        currentDialog.show(title, defaultText, hint, listener);
    }
    
    public void hideCurrentDialog() {
        if (currentDialog != null) {
            currentDialog.hide();
            currentDialog = null;
        }
    }
    
    public boolean isDialogShowing() {
        return currentDialog != null;
    }
}

Enhanced Text Input with Filtering

public class GameTextInput extends PlaceholderTextBox {
    private InputType inputType;
    
    public enum InputType {
        ALPHA_ONLY,
        NUMERIC_ONLY,
        ALPHANUMERIC,
        EMAIL,
        PASSWORD,
        CUSTOM
    }
    
    public GameTextInput(InputType type) {
        super();
        this.inputType = type;
        setupInputFilter();
        setupStyling();
    }
    
    public GameTextInput(String placeholder, InputType type) {
        super(placeholder);
        this.inputType = type;
        setupInputFilter();
        setupStyling();
    }
    
    private void setupInputFilter() {
        switch (inputType) {
            case ALPHA_ONLY:
                setInputFilter(new InputFilter() {
                    @Override
                    public boolean accept(char c) {
                        return Character.isLetter(c) || Character.isWhitespace(c);
                    }
                    
                    @Override
                    public String filter(String input) {
                        return input.replaceAll("[^a-zA-Z\\s]", "");
                    }
                });
                break;
                
            case NUMERIC_ONLY:
                setInputFilter(new InputFilter() {
                    @Override
                    public boolean accept(char c) {
                        return Character.isDigit(c) || c == '.' || c == '-';
                    }
                    
                    @Override
                    public String filter(String input) {
                        return input.replaceAll("[^0-9.-]", "");
                    }
                });
                break;
                
            case ALPHANUMERIC:
                setInputFilter(new InputFilter() {
                    @Override
                    public boolean accept(char c) {
                        return Character.isLetterOrDigit(c) || Character.isWhitespace(c);
                    }
                    
                    @Override
                    public String filter(String input) {
                        return input.replaceAll("[^a-zA-Z0-9\\s]", "");
                    }
                });
                break;
                
            case EMAIL:
                setInputFilter(new InputFilter() {
                    @Override
                    public boolean accept(char c) {
                        return Character.isLetterOrDigit(c) || c == '@' || c == '.' || c == '_' || c == '-';
                    }
                    
                    @Override
                    public String filter(String input) {
                        return input.replaceAll("[^a-zA-Z0-9@._-]", "").toLowerCase();
                    }
                });
                break;
        }
    }
    
    private void setupStyling() {
        // Add focus/blur styling
        addFocusHandler(new FocusHandler() {
            @Override
            public void onFocus(FocusEvent event) {
                getElement().getStyle().setBorderColor("#4CAF50");
                getElement().getStyle().setProperty("boxShadow", "0 0 5px rgba(76, 175, 80, 0.5)");
            }
        });
        
        addBlurHandler(new BlurHandler() {
            @Override
            public void onBlur(BlurEvent event) {
                getElement().getStyle().setBorderColor("#ccc");
                getElement().getStyle().setProperty("boxShadow", "none");
                
                // Validate input on blur
                validateInput();
            }
        });
        
        // Real-time validation
        addValueChangeHandler(new ValueChangeHandler<String>() {
            @Override
            public void onValueChange(ValueChangeEvent<String> event) {
                validateInput();
            }
        });
    }
    
    private void validateInput() {
        String value = getText();
        boolean isValid = true;
        
        switch (inputType) {
            case EMAIL:
                isValid = value.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
                break;
            case NUMERIC_ONLY:
                try {
                    Double.parseDouble(value);
                } catch (NumberFormatException e) {
                    isValid = !value.isEmpty();
                }
                break;
        }
        
        setErrorStyle(!isValid);
    }
    
    public boolean isValidInput() {
        validateInput();
        return !hasErrorStyle();
    }
    
    public String getValidatedText() {
        if (isValidInput()) {
            return getText();
        }
        return null;
    }
}

Responsive Widget Layout Manager

public class ResponsiveLayoutManager {
    private ResizableWidgetCollection widgets;
    private Map<ResizableWidget, LayoutConstraints> constraints;
    
    public static class LayoutConstraints {
        public float percentX, percentY; // Position as percentage of screen
        public float percentWidth, percentHeight; // Size as percentage of screen
        public int minWidth, minHeight; // Minimum pixel sizes
        public int maxWidth, maxHeight; // Maximum pixel sizes
        public Anchor anchor; // Anchor point for positioning
        
        public enum Anchor {
            TOP_LEFT, TOP_CENTER, TOP_RIGHT,
            MIDDLE_LEFT, MIDDLE_CENTER, MIDDLE_RIGHT,
            BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT
        }
    }
    
    public ResponsiveLayoutManager() {
        widgets = new ResizableWidgetCollection();
        constraints = new HashMap<>();
        
        // Listen for window resize events
        Window.addResizeHandler(new ResizeHandler() {
            @Override
            public void onResize(ResizeEvent event) {
                layoutAllWidgets();
            }
        });
    }
    
    public void addWidget(ResizableWidget widget, LayoutConstraints layoutConstraints) {
        widgets.add(widget);
        constraints.put(widget, layoutConstraints);
        layoutWidget(widget, layoutConstraints);
    }
    
    public void removeWidget(ResizableWidget widget) {
        widgets.remove(widget);
        constraints.remove(widget);
    }
    
    public void layoutAllWidgets() {
        for (ResizableWidget widget : widgets) {
            LayoutConstraints constraint = constraints.get(widget);
            if (constraint != null) {
                layoutWidget(widget, constraint);
            }
        }
    }
    
    private void layoutWidget(ResizableWidget widget, LayoutConstraints constraint) {
        int screenWidth = Gdx.graphics.getWidth();
        int screenHeight = Gdx.graphics.getHeight();
        
        // Calculate size
        int width = (int)(screenWidth * constraint.percentWidth);
        int height = (int)(screenHeight * constraint.percentHeight);
        
        // Apply size constraints
        width = Math.max(constraint.minWidth, Math.min(constraint.maxWidth, width));
        height = Math.max(constraint.minHeight, Math.min(constraint.maxHeight, height));
        
        // Calculate position based on anchor
        int x = calculateAnchoredX(screenWidth, width, constraint);
        int y = calculateAnchoredY(screenHeight, height, constraint);
        
        // Apply layout
        widget.resize(width, height);
        
        // Set position if widget supports it
        if (widget instanceof Widget) {
            ((Widget) widget).setPixelSize(width, height);
            // Position setting depends on widget implementation
        }
    }
    
    private int calculateAnchoredX(int screenWidth, int widgetWidth, LayoutConstraints constraint) {
        int baseX = (int)(screenWidth * constraint.percentX);
        
        switch (constraint.anchor) {
            case TOP_LEFT:
            case MIDDLE_LEFT:
            case BOTTOM_LEFT:
                return baseX;
            case TOP_CENTER:
            case MIDDLE_CENTER:
            case BOTTOM_CENTER:
                return baseX - widgetWidth / 2;
            case TOP_RIGHT:
            case MIDDLE_RIGHT:
            case BOTTOM_RIGHT:
                return baseX - widgetWidth;
            default:
                return baseX;
        }
    }
    
    private int calculateAnchoredY(int screenHeight, int widgetHeight, LayoutConstraints constraint) {
        int baseY = (int)(screenHeight * constraint.percentY);
        
        switch (constraint.anchor) {
            case TOP_LEFT:
            case TOP_CENTER:
            case TOP_RIGHT:
                return baseY;
            case MIDDLE_LEFT:
            case MIDDLE_CENTER:
            case MIDDLE_RIGHT:
                return baseY - widgetHeight / 2;
            case BOTTOM_LEFT:
            case BOTTOM_CENTER:
            case BOTTOM_RIGHT:
                return baseY - widgetHeight;
            default:
                return baseY;
        }
    }
    
    // Predefined constraint builders
    public static LayoutConstraints centerScreen(float percentWidth, float percentHeight) {
        LayoutConstraints constraints = new LayoutConstraints();
        constraints.percentX = 0.5f;
        constraints.percentY = 0.5f;
        constraints.percentWidth = percentWidth;
        constraints.percentHeight = percentHeight;
        constraints.anchor = LayoutConstraints.Anchor.MIDDLE_CENTER;
        constraints.minWidth = 100;
        constraints.minHeight = 50;
        constraints.maxWidth = Integer.MAX_VALUE;
        constraints.maxHeight = Integer.MAX_VALUE;
        return constraints;
    }
    
    public static LayoutConstraints bottomCenter(float percentWidth, float height) {
        LayoutConstraints constraints = new LayoutConstraints();
        constraints.percentX = 0.5f;
        constraints.percentY = 0.1f;
        constraints.percentWidth = percentWidth;
        constraints.percentHeight = 0; // Fixed height
        constraints.anchor = LayoutConstraints.Anchor.BOTTOM_CENTER;
        constraints.minWidth = 200;
        constraints.minHeight = (int)height;
        constraints.maxWidth = Integer.MAX_VALUE;
        constraints.maxHeight = (int)height;
        return constraints;
    }
}

Web-Specific Widget Considerations

Browser Integration

// Widgets are designed for web browser environments
public class BrowserIntegrationHelper {
    
    public static void configureForMobile() {
        // Optimize widgets for mobile browsers
        ProgressBar.setDefaultHeight(40); // Larger for touch
        TextInputDialogBox.setDefaultAnimationDuration(200); // Faster for mobile
        
        // Handle virtual keyboard
        PlaceholderTextBox.addGlobalFocusHandler(new FocusHandler() {
            @Override
            public void onFocus(FocusEvent event) {
                // Scroll input into view when virtual keyboard appears
                Element element = event.getSource().getElement();
                element.scrollIntoView();
            }
        });
    }
    
    public static void configureForDesktop() {
        // Optimize for desktop browsers
        ProgressBar.setDefaultHeight(24); // Standard height
        TextInputDialogBox.setDefaultAnimationDuration(300); // Smooth animations
        
        // Enable advanced keyboard shortcuts
        configureKeyboardShortcuts();
    }
    
    private static void configureKeyboardShortcuts() {
        // Add Ctrl+A, Ctrl+C, Ctrl+V support for text inputs
        // This is handled automatically by PlaceholderTextBox
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-badlogicgames-gdx--gdx-backend-gwt

docs

application.md

audio.md

files.md

graphics.md

index.md

input.md

networking.md

preloader.md

webaudio.md

widgets.md

tile.json