Skip to main content
Version: Latest

Region Building with Position Integration

Create regions using flexible positioning with the RegionBuilder and Position integration for precise placement.

Overviewโ€‹

The RegionBuilder class provides a fluent API for creating regions with precise positioning. By integrating with the Position class and Positions.Name enum, it offers both absolute pixel positioning and percentage-based placement options.

Key Featuresโ€‹

  • Absolute Positioning: Define regions using exact pixel coordinates
  • Position Integration: Leverage the Position class for percentage-based placement
  • Named Positions: Use semantic positions like TOPLEFT, MIDDLEMIDDLE, BOTTOMRIGHT
  • Relative Positioning: Position regions relative to other regions
  • Percentage-Based Sizing: Define regions as percentages of screen size
  • Fluent API: Chain methods for readable region construction

Basic Usageโ€‹

Creating a RegionBuilderโ€‹

import io.github.jspinak.brobot.model.element.Region;
import io.github.jspinak.brobot.model.element.RegionBuilder;
import io.github.jspinak.brobot.model.element.Position;
import static io.github.jspinak.brobot.model.element.Positions.Name.*;

// Access the builder through Region's static method
Region region = Region.builder()
.withSize(200, 150)
.build();

Absolute Positioningโ€‹

// Simple region with absolute coordinates
Region absolute = Region.builder()
.withRegion(100, 100, 200, 150) // x, y, width, height
.build();

// Position and size separately
Region separate = Region.builder()
.withPosition(50, 75)
.withSize(300, 200)
.build();

Position-Based Placementโ€‹

Using Position Objectsโ€‹

The Position class provides percentage-based coordinates (typically 0.0 to 1.0, though values outside this range are allowed for off-screen positioning) for resolution-independent placement:

// Place region at 70% width, 30% height of screen
Region customPos = Region.builder()
.withSize(200, 150)
.withPosition(new Position(0.7, 0.3))
.build();

// Center of screen using Position
Region centered = Region.builder()
.withSize(400, 300)
.withPosition(new Position(0.5, 0.5))
.build();

Named Positionsโ€‹

Use the Positions.Name enum for semantic positioning:

// Quick placement using named positions
Region topRight = Region.builder()
.withSize(300, 200)
.withPosition(TOPRIGHT)
.build();

Region bottomCenter = Region.builder()
.withSize(250, 100)
.withPosition(BOTTOMMIDDLE)
.build();

// All available named positions:
// TOPLEFT, TOPMIDDLE, TOPRIGHT
// MIDDLELEFT, MIDDLEMIDDLE, MIDDLERIGHT
// BOTTOMLEFT, BOTTOMMIDDLE, BOTTOMRIGHT

Convenience Methodsโ€‹

RegionBuilder provides helper methods for common positions:

// Center on screen
Region dialog = Region.builder()
.withSize(600, 400)
.centerOnScreen()
.build();

// Corner positions
Region topLeft = Region.builder()
.withSize(100, 100)
.topLeft()
.build();

Region bottomRight = Region.builder()
.withSize(120, 80)
.bottomRight()
.build();

// Edge positions
Region topBar = Region.builder()
.withScreenPercentageSize(1.0, 0.1) // Full width, 10% height
.topCenter()
.build();

Region sidebar = Region.builder()
.withScreenPercentageSize(0.2, 1.0) // 20% width, full height
.leftCenter()
.build();

Screen Percentage Sizingโ€‹

Define regions as percentages of screen dimensions:

// Size as percentage of screen
Region halfScreen = Region.builder()
.withScreenPercentageSize(0.5, 0.5) // 50% width, 50% height
.centerOnScreen()
.build();

// Position and size using percentages
Region searchArea = Region.builder()
.withScreenPercentage(0.1, 0.1, 0.8, 0.3) // x%, y%, width%, height%
.build();

// Just percentage size (position separately)
Region percentSized = Region.builder()
.withScreenPercentageSize(0.3, 0.4)
.topRight()
.build();

Relative Positioningโ€‹

Position regions relative to other regions:

Region mainWindow = Region.builder()
.withSize(800, 600)
.centerOnScreen()
.build();

// Position tooltip above the main window
Region tooltip = Region.builder()
.withSize(200, 50)
.positionRelativeTo(mainWindow, TOPMIDDLE)
.adjustY(-10) // 10px gap above
.build();

// Position button in bottom-right of window
Region button = Region.builder()
.withSize(100, 40)
.positionRelativeTo(mainWindow, BOTTOMRIGHT)
.adjustX(-10) // 10px margin from right
.adjustY(-10) // 10px margin from bottom
.build();

// Custom relative position (25% from left, 75% from top)
Region marker = Region.builder()
.withSize(20, 20)
.positionRelativeTo(mainWindow, new Position(0.25, 0.75))
.build();

Predefined Screen Regionsโ€‹

Quick methods for common screen divisions:โ€‹

// Full screen
Region fullScreen = Region.builder()
.fullScreen()
.build();

// Half regions
Region topHalf = Region.builder()
.topHalf()
.build();

Region bottomHalf = Region.builder()
.bottomHalf()
.build();

Region leftHalf = Region.builder()
.leftHalf()
.build();

Region rightHalf = Region.builder()
.rightHalf()
.build();

Adjustments and Modificationsโ€‹

Fine-tuning Position and Sizeโ€‹

// Adjust individual dimensions
Region adjusted = Region.builder()
.withRegion(100, 100, 200, 150)
.adjustX(10) // Move 10px right
.adjustY(-20) // Move 20px up
.adjustWidth(50) // Increase width by 50px
.adjustHeight(30) // Increase height by 30px
.build();

// Adjust all at once
Region bulkAdjusted = Region.builder()
.withRegion(100, 100, 200, 150)
.adjustBy(10, -5, 20, 20) // x, y, width, height adjustments
.build();

Expanding and Contractingโ€‹

// Expand region by pixels on all sides
Region expanded = Region.builder()
.withRegion(100, 100, 200, 150)
.expand(20) // Grows by 20px on all sides
.build();
// Result: x=80, y=80, width=240, height=190

// Contract region (negative expansion)
Region contracted = Region.builder()
.withRegion(100, 100, 200, 150)
.expand(-10) // Shrinks by 10px on all sides
.build();

Working with Existing Regionsโ€‹

Region original = new Region(100, 100, 200, 150);

// Modify existing region
Region modified = Region.builder()
.fromRegion(original)
.adjustWidth(50)
.adjustHeight(50)
.build();

// Create region relative to existing
Region adjacent = Region.builder()
.fromRegion(original)
.adjustX(original.getW() + 10) // Position to the right
.build();

Custom Anchoringโ€‹

Control how regions are positioned using anchor points:

// Default behavior (no anchor set) - position specifies top-left corner
Region defaultAnchor = Region.builder()
.withSize(100, 100)
.withPosition(500, 300) // Top-left corner at (500, 300)
.build();

// Center anchor - positions region at screen center
Region centerAnchor = Region.builder()
.withSize(100, 100)
.withAnchor(MIDDLEMIDDLE) // Places at screen center
.build();
// Result: Region centered on screen at ((screenWidth-100)/2, (screenHeight-100)/2)

// Custom anchor for screen-relative positioning
Region customAnchor = Region.builder()
.withSize(100, 100)
.withAnchor(new Position(0.75, 0.25)) // 75% from left, 25% from top
.build();
// Result: Positioned at (screenWidth*0.75 - 50, screenHeight*0.25 - 25)

Constraintsโ€‹

Screen Boundary Constraintsโ€‹

// Constrain to screen boundaries (default: true)
Region constrained = Region.builder()
.withPosition(10000, 10000) // Way off screen
.withSize(200, 150)
.constrainToScreen(true)
.build();
// Will be repositioned to stay within screen bounds

// Allow off-screen positioning
Region offScreen = Region.builder()
.withPosition(-50, -50)
.withSize(200, 150)
.constrainToScreen(false)
.build();
// Maintains negative coordinates

Aspect Ratio Maintenanceโ€‹

// Maintain aspect ratio when resizing
Region aspectLocked = Region.builder()
.withSize(400, 300) // 4:3 ratio
.maintainAspectRatio(true)
.withWidth(600) // Height automatically becomes 450
.build();

Complex Layout Examplesโ€‹

Dashboard Layoutโ€‹

// Create a dashboard with header, sidebar, and content area
Region header = Region.builder()
.withScreenPercentageSize(1.0, 0.1) // Full width, 10% height
.topCenter()
.build();

Region sidebar = Region.builder()
.withScreenPercentageSize(0.2, 0.9) // 20% width, 90% height
.positionRelativeTo(header, BOTTOMLEFT)
.build();

Region content = Region.builder()
.positionRelativeTo(sidebar, MIDDLERIGHT)
.withScreenPercentageSize(0.8, 0.9)
.build();

Region footer = Region.builder()
.withScreenPercentageSize(1.0, 0.05)
.bottomCenter()
.build();
// Semi-transparent overlay
Region overlay = Region.builder()
.fullScreen()
.build();

// Centered modal dialog
Region modal = Region.builder()
.withScreenPercentageSize(0.5, 0.6) // 50% width, 60% height
.centerOnScreen()
.build();

// Close button in modal's top-right
Region closeButton = Region.builder()
.withSize(30, 30)
.positionRelativeTo(modal, TOPRIGHT)
.adjustX(-10)
.adjustY(10)
.build();

Grid Layoutโ€‹

import java.util.List;
import java.util.ArrayList;

// Create a 3x3 grid of regions
List<Region> grid = new ArrayList<>();
double cellWidth = 0.33;
double cellHeight = 0.33;

for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
Region cell = Region.builder()
.withScreenPercentage(
col * cellWidth, // x position
row * cellHeight, // y position
cellWidth * 0.9, // width with gap
cellHeight * 0.9 // height with gap
)
.build();
grid.add(cell);
}
}

Best Practicesโ€‹

1. Use Percentages for Cross-Platform Compatibilityโ€‹

// Good: Percentage-based, works on any screen
Region adaptive = Region.builder()
.withScreenPercentageSize(0.3, 0.4)
.centerOnScreen()
.build();

// Avoid: Fixed pixels may not work on different screens
Region fixed = Region.builder()
.withRegion(640, 360, 640, 480)
.build();

2. Use Direct Coordinates for Pixel-Perfect Placementโ€‹

// Specify exact pixel coordinates when precision is needed
Region precise = Region.builder()
.withPosition(500, 300)
.withSize(400, 200)
.build();

3. Use Named Positions for Clarityโ€‹

// Clear intent
Region notification = Region.builder()
.withSize(300, 100)
.topRight()
.adjustX(-20)
.adjustY(20)
.build();

// Less clear
Region notification2 = Region.builder()
.withSize(300, 100)
.withAnchor(new Position(1.0, 0.0))
.build();

4. Combine Relative and Absolute Positioningโ€‹

// Start with relative, fine-tune with absolute
Region precise = Region.builder()
.withScreenPercentageSize(0.25, 0.2)
.centerOnScreen()
.adjustX(-10) // Fine adjustments
.adjustY(5)
.build();

5. Use Percentage-Based Sizing for Flexibilityโ€‹

// Create regions that work well at any resolution
Region flexible = Region.builder()
.withScreenPercentage(0.1, 0.1, 0.8, 0.8) // 10% margins, 80% of screen
.build();

// Verify region is properly defined
assert flexible.isDefined();
assert flexible.getW() > 0 && flexible.getH() > 0;

Integration with Brobot Actionsโ€‹

RegionBuilder-created regions work seamlessly with Brobot's Action API for clicking, typing, and pattern matching. For complete Action API documentation, see ActionConfig Overview and ActionConfig Examples.

For more on States and the @State annotation, see States Guide and Annotations Reference.

Using RegionBuilder in State Definitionsโ€‹

import io.github.jspinak.brobot.actions.Action;
import io.github.jspinak.brobot.model.element.Region;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static io.github.jspinak.brobot.model.element.Positions.Name.*;

@Component
public class LoginPageController {

@Autowired
private Action action;

private final Region usernameField = Region.builder()
.withScreenPercentage(0.4, 0.4, 0.2, 0.05)
.build();

private final Region passwordField = Region.builder()
.positionRelativeTo(usernameField, BOTTOMMIDDLE)
.withSize(usernameField.getW(), usernameField.getH())
.adjustY(20)
.build();

private final Region loginButton = Region.builder()
.positionRelativeTo(passwordField, BOTTOMMIDDLE)
.withSize(100, 40)
.adjustY(30)
.build();

// Use regions with Brobot actions
public void login(String username, String password) {
// Click and type in username field
action.click(usernameField);
action.type(username);

// Click and type in password field
action.click(passwordField);
action.type(password);

// Click login button
action.click(loginButton);
}
}

Dynamic Region Creationโ€‹

import io.github.jspinak.brobot.actions.Action;
import io.github.jspinak.brobot.model.element.Region;
import io.github.jspinak.brobot.model.element.StateImage;
import io.github.jspinak.brobot.core.screen.ScreenDimensions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class AdaptiveSearch {

@Autowired
private Action action;

public Region getSearchAreaForScreen() {
// Detect current screen size using Brobot's ScreenDimensions
int screenWidth = ScreenDimensions.getWidth();

if (screenWidth > 2000) {
// Large screen: search in center third
return Region.builder()
.withScreenPercentage(0.33, 0.33, 0.34, 0.34)
.build();
} else if (screenWidth > 1400) {
// Medium screen: search in center half
return Region.builder()
.withScreenPercentageSize(0.5, 0.5)
.centerOnScreen()
.build();
} else {
// Small screen: search most of screen
return Region.builder()
.withScreenPercentage(0.1, 0.1, 0.8, 0.8)
.build();
}
}

// Example usage with pattern matching
public void performAdaptiveSearch(StateImage pattern) {
Region searchArea = getSearchAreaForScreen();
action.find(pattern).inRegion(searchArea);
}
}

Troubleshootingโ€‹

For visual debugging of regions, use the highlighting feature to see regions on screen. For complete configuration options, see the Properties Reference. For handling different screen resolutions and DPI settings, see the DPI Resolution Guide.

Region Outside Screen Boundsโ€‹

// Problem: Region appears cut off
Region problem = Region.builder()
.withPosition(1800, 1000)
.withSize(300, 200)
.build();

// Solution: Enable screen constraints
Region solution = Region.builder()
.withPosition(1800, 1000)
.withSize(300, 200)
.constrainToScreen(true) // Ensures region stays on screen
.build();

Size Issuesโ€‹

// Problem: Region too small for reliable clicking
Region tooSmall = Region.builder()
.withPosition(100, 100)
.withSize(5, 5) // Too small!
.build();

// Solution: Use appropriate minimum sizes
Region clickable = Region.builder()
.withPosition(100, 100)
.withSize(50, 30) // Reasonable click target
.build();

// Or use percentage-based sizing for flexibility
Region flexible = Region.builder()
.withScreenPercentage(0.1, 0.1, 0.05, 0.03) // 5% width, 3% height
.build();

Understanding Anchor Behaviorโ€‹

// Important: Anchors are screen-relative, not position-relative
Region screenCentered = Region.builder()
.withSize(100, 100)
.withAnchor(MIDDLEMIDDLE) // Places region at screen center
.build();
// Result: Positioned at ((screenWidth-100)/2, (screenHeight-100)/2)

// Anchors ignore withPosition() - they use screen dimensions
Region alsoScreenCentered = Region.builder()
.withSize(100, 100)
.withAnchor(MIDDLEMIDDLE)
.withPosition(500, 300) // This is IGNORED when anchor is set!
.build();
// Result: Still positioned at screen center, NOT at (500, 300)

// Solution: For specific positioning, don't use anchors
Region specificPosition = Region.builder()
.withSize(100, 100)
.withPosition(500, 300) // Top-left at (500, 300)
.build();

Summaryโ€‹

The enhanced RegionBuilder with Position integration provides:

  • Resolution Independence: Define once, run anywhere
  • Intuitive API: Named positions and percentage-based sizing
  • Flexibility: Combine relative and absolute positioning
  • Maintainability: Clear, readable region definitions
  • Adaptability: Automatic scaling between resolutions

Use RegionBuilder to create robust, screen-adaptive automation that works consistently across different environments and display configurations.

Next Stepsโ€‹