Style, Colors and UI
FluxRender.ui.Button
Button(text: str, on_click: Callable, x_pos: int = 0, y_pos: int = 50, width: int = 150, height: int = 50, align: Align = Align.LEFT_TOP, style: UIStyle = None)
Bases: UIWidget
Represents an interactive button widget in the UI system.
This class extends UIWidget to provide a clickable element with a text label.
It manages its own visual state transitions (idle, hover, active) and efficiently
updates GPU-accessible color fields (ti.field) for rendering.
Key Features:
- Dynamic Styling: Automatically updates text and background colors based on mouse interaction.
- Smart Callbacks: Inspects the provided
on_clickhandler to optionally pass the button instance as an argument. - Text Rendering: Handles text texture baking for the button label.
- Alignment: Supports various anchor points (e.g., Center, Top-Left) for flexible positioning.
Initializes a new Button widget with interactive behavior and dynamic styling.
The button handles mouse interactions (hover, click) and renders text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The label text displayed on the button. |
required |
on_click
|
callable
|
The function to execute when the button is clicked. This function can accept 0 arguments or 1 argument (the Button instance). |
required |
x_pos
|
int
|
The horizontal position coordinate in pixels. Defaults to 0. |
0
|
y_pos
|
int
|
The vertical position coordinate in pixels. Defaults to 50. |
50
|
width
|
int
|
The width of the button in pixels. Defaults to 150. |
150
|
height
|
int
|
The height of the button in pixels. Defaults to 50. |
50
|
align
|
Align
|
The alignment anchor point relative to the (x_pos, y_pos) coordinates (e.g., LEFT_TOP, CENTER). Defaults to Align.LEFT_TOP. |
LEFT_TOP
|
style
|
UIStyle
|
A styling object defining colors and fonts. If None, default styling is used. |
None
|
Example
Creating a button that changes the color_property of a VectorField when clicked:
import FluxRender as fr
# [Initializing the scene and coordinate system]
# Create a vector field
vector_field = fr.VectorField(vec_function=lambda x, y: (y, -x))
# Define function to toggle vector field color
def toggle_color():
if vector_field.color_property == fr.Property.VELOCITY:
vector_field.color_property = fr.Property.DIVERGENCE
else:
vector_field.color_property = fr.Property.VELOCITY
# Create a button with the toggle function
button = fr.Button(
text = "Change Property",
on_click = toggle_color,
style = fr.UIStyle(
font_size=15
)
)
scene.add(vector_field, button)
Source code in FluxRender/ui.py
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | |
is_hovered
A method to check if the cursor position matches the button area
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene
|
Scene
|
Scene object |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the mouse is hovering over the button, False otherwise |
Source code in FluxRender/ui.py
FluxRender.ui.Axis
Axis(color: Sequence[float] = (1.0, 1.0, 1.0, 1.0), thickness: float = 2.5, label_size: int = 14, label_color: Sequence[float] = (1, 1, 1, 1), label_density: int = 10, label_offset_x: Sequence[float] = (0, -4), label_offset_y: Sequence[float] = (-4, 0), label_offset_0: Sequence[float] = (-4, -4), cover_background: bool = False, antyaliasing: bool = True, draw_arrows: bool = True, arrow_size: float = 25, arrow_style: ArrowStyle = ArrowStyle.HARPOON, arrow_color: Sequence[float] = (0.8, 0.8, 0.8, 1.0))
Bases: Renderable
Renders 2D coordinate axes with dynamic, GPU-accelerated labels.
This class handles the drawing of the main X and Y axes lines using SDF (Signed Distance Fields) for anti-aliasing, and manages the batch rendering of textual labels via a texture atlas. It supports dynamic level-of-detail (LOD) for label density and customizable positioning.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
color
|
Sequence[float]
|
The RGBA color of the axis lines (0.0 to 1.0). |
(1.0, 1.0, 1.0, 1.0)
|
thickness
|
float
|
The thickness of the axis lines in pixels. |
2.5
|
label_size
|
int
|
The base font size used for label layout calculations. |
14
|
label_color
|
Sequence[float]
|
The RGBA color tint applied to the text labels. |
(1, 1, 1, 1)
|
label_density
|
int
|
A divisor for the screen dimension to determine target step size. Higher values result in more frequent labels (tighter spacing), while lower values result in fewer labels. Similar to the density logic in Grid. |
10
|
label_offset_x
|
Sequence[float]
|
A tuple (dx, dy) in pixels indicating the rendering offset for labels along the X-axis. Used to center or position text relative to the tick mark. |
(0, -4)
|
label_offset_y
|
Sequence[float]
|
A tuple (dx, dy) in pixels indicating the rendering offset for labels along the Y-axis. |
(-4, 0)
|
label_offset_0
|
Sequence[float]
|
A tuple (dx, dy) in pixels specifically for the origin (0, 0) label, usually positioned in a quadrant to avoid overlapping both axes. |
(-4, -4)
|
cover_background
|
bool
|
If True, disables alpha blending for the text pixels. Instead of mixing with the background, the text color strictly overwrites the destination pixels. This is useful for making labels "erase" or cover underlying grid lines to improve legibility. |
False
|
antyaliasing
|
bool
|
If True, smooths the edges of the axis lines (default True) |
True
|
draw_arrows
|
bool
|
If True, draws arrows at the ends of the axes (default True) |
True
|
arrow_size
|
float
|
The size of the arrows in pixels (default 10.0) |
25
|
arrow_style
|
ArrowStyle
|
The style of the arrows (default ArrowStyle.HARPOON) |
HARPOON
|
arrow_color
|
Sequence[float]
|
The RGBA color of the arrows (0.0 to 1.0). |
(0.8, 0.8, 0.8, 1.0)
|
Example
Creating a yellow coordinate axis with large labels that cover the elements behind them (such as grid lines):
import FluxRender as fr
# [Initializing the scene and coordinate system]
axis = fr.Axis(
color = (1, 0.8, 0, 1), # Yellow axes
label_size = 18, # Larger font size for labels
label_color = (1, 0.8, 0, 1), # Yellow labels
cover_background = True, # Make labels cover elements behind them
arrow_color = (1, 0.8, 0, 1) # Yellow arrows
)
scene.add(axis)
Source code in FluxRender/ui.py
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 | |
FluxRender.ui.Grid
Bases: Renderable
Creates a visible grid on the coordinate system that adjusts depending on zoom. Supports custom color, thickness, density, and anti-aliasing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
color
|
tuple / list
|
The RGBA color of the grid lines. Defaults to (0.6, 0.6, 0.6, 1). |
(0.6, 0.6, 0.6, 1)
|
thickness
|
float
|
The thickness of the grid lines in pixels. Defaults to 1. |
1
|
density
|
int
|
The target number of grid lines across the visible range (higher means more lines). Defaults to 10. |
10
|
antyaliasing
|
bool
|
Whether to apply anti-aliasing. Defaults to True. |
True
|
Example
Creating a double grid with different colors and densities:
import FluxRender as fr
# [Initializing the scene and coordinate system]
# Create a main grid with lower density
main_grid = fr.Grid()
# Create a secondary, less prominent grid with higher density
secondary_grid = fr.Grid(
color=(0.6, 0.6, 0.6, 0.5), # More transparent
density=50
)
scene.add(main_grid, secondary_grid)
Source code in FluxRender/ui.py
FluxRender.ui.UIStyle
dataclass
UIStyle(background_color: Optional[Sequence[float]] = None, hover_background_color: Optional[Sequence[float]] = None, active_background_color: Optional[Sequence[float]] = None, text_color: Optional[Sequence[float]] = None, hover_text_color: Optional[Sequence[float]] = None, text_stroke: Optional[int] = None, text_stroke_color: Optional[Sequence[float]] = None, active_text_color: Optional[Sequence[float]] = None, border_radius: Optional[int] = None, font_size: Optional[int] = None, padding: Optional[Tuple[int, int]] = None, display: Optional[bool] = None, visible: Optional[bool] = None)
A highly flexible, CSS-like styling configuration for UI elements.
Unlike rigid styling properties, UIStyle utilizes a cascading resolution system.
By default, all attributes are initialized to None. This allows elements to
intelligently inherit properties from their parent containers or fall back to
their class-specific and global default themes.
The Cascading Resolution Order
When a UI element needs to render, it resolves its style properties in this exact order: 1. Instance Override: Is it explicitly set in this specific UIStyle instance? 2. Parent Inheritance: If the property is inheritable, does the parent container have it set? 3. Class Default: What is the natural default for this element type (e.g., Button vs. Container)? 4. Global Theme: The ultimate fallback theme defined by the engine.
Inheritable vs. Non-Inheritable Properties
- Inheritable Properties: Typography and deep layout states (e.g.,
text_color,display). If you set these on a container, all child elements inside will inherit them. - Non-Inheritable Properties: Physical bounds and surface appearances (e.g.,
background_color,padding,visible). Setting a red background on a container will NOT make its inner buttons red.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
background_color
|
Optional[Sequence[float]]
|
The background color of the widget in RGBA format. |
None
|
hover_background_color
|
Optional[Sequence[float]]
|
The background color when the mouse hovers over the widget. |
None
|
active_background_color
|
Optional[Sequence[float]]
|
The background color when the widget is active (e.g., clicked). |
None
|
text_color
|
Optional[Sequence[float]]
|
(Inheritable) The color of the text in RGBA format. |
None
|
hover_text_color
|
Optional[Sequence[float]]
|
(Inheritable) The color of the text when the mouse hovers. |
None
|
text_stroke
|
Optional[int]
|
(Inheritable) The width of the stroke around the text. |
None
|
text_stroke_color
|
Optional[Sequence[float]]
|
(Inheritable) The color of the stroke around the text. |
None
|
active_text_color
|
Optional[Sequence[float]]
|
(Inheritable) The color of the text when the widget is active. |
None
|
border_radius
|
Optional[int]
|
Corner rounding radius. |
None
|
font_size
|
Optional[int]
|
(Inheritable) The size of the font used for the widget's text. |
None
|
padding
|
Optional[Tuple[int, int]]
|
Inner spacing (x, y) between the widget's border and its internal content. |
None
|
display
|
Optional[bool]
|
(Inheritable) Toggles rendering for both the element AND all of its children. |
None
|
visible
|
Optional[bool]
|
Toggles rendering for the element's surface only. Children remain drawn. |
None
|
Example
Creating a button with custom styling:
import FluxRender as fr
# [Initializing the scene and coordinate system]
# Create a container style with a warning aesthetic.
# Background is explicitly red, and text is explicitly yellow.
warning_panel_style = fr.UIStyle(
background_color = (1.0, 0.0, 0.0, 0.5),
text_color = (1.0, 1.0, 0.0, 1.0)
)
warning_container = fr.VBox(x_pos=100, y_pos=100, style=warning_panel_style)
# Define function to handle button click
def acknowledge_warning():
print("Warning acknowledged!")
# Create a button WITHOUT passing any specific style.
# It will use its default button background, but intelligently inherit the yellow text color from the warning container.
action_button = fr.Button(
text = "Understood",
on_click = acknowledge_warning
)
warning_container.add(action_button)
scene.add(warning_container)
FluxRender.ui.VBox
VBox(x_pos: int, y_pos: int, spacing: int = 15, align: Align = Align.LEFT_TOP, common_width: int = None, common_height: int = None, style: UIStyle = None)
Bases: Container
A vertical layout manager that automatically stacks its children from top to bottom.
The VBox utilizes a deferred layout resolution system. It does not calculate positions immediately upon adding elements. Instead, it waits until the entire UI tree is constructed, and then recursively computes bounding boxes (bottom-up) and element coordinates (top-down). This ensures pixel-perfect alignment regardless of the order in which nested containers and widgets are added.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_pos
|
int
|
The starting X coordinate (anchor point) of the container. |
required |
y_pos
|
int
|
The starting Y coordinate (anchor point) of the container. |
required |
spacing
|
int
|
The number of pixels inserted vertically between each child element. |
15
|
align
|
Align
|
The alignment method that objects in the container will inherit. |
LEFT_TOP
|
common_width
|
int
|
Forces a uniform width for all DIRECT children (e.g., Buttons) added to this specific container. Does not affect deeply nested elements. |
None
|
common_height
|
int
|
Forces a uniform height for all DIRECT children added to this specific container. Does not affect deeply nested elements. |
None
|
style
|
UIStyle
|
The UIStyle object dictating the container's appearance (e.g., background, padding). Inheritable properties provided here will cascade to all children. |
None
|
Example
Creating a vertical set of three buttons:
import FluxRender as fr
# [Inicialize the scene and coordinate system]
# Define the container for the buttons
vertical_container = fr.VBox(30, 400, common_height=40, common_width=290)
# Create a function called by buttons
def print_name(button):
print(f"Button pressed: {button.text}")
# Create buttons
button1 = fr.Button("Orange", print_name)
button2 = fr.Button("Blue", print_name)
button3 = fr.Button("Green", print_name)
# Add buttons to the container
vertical_container.add(button1, button2, button3)
# Add the container to the scene
scene.add(vertical_container)
Source code in FluxRender/ui.py
FluxRender.ui.HBox
HBox(x_pos: int, y_pos: int, spacing: int = 15, align: Align = Align.LEFT_TOP, common_width: int = None, common_height: int = None, style: UIStyle = None)
Bases: Container
A horizontal layout manager that automatically arranges its children from left to right.
The HBox relies on a robust deferred layout architecture. By separating the hierarchy building phase from the mathematical layout phase, it can dynamically adapt its own bounding box to wrap exactly around its content, making it highly scalable for complex, nested UI structures.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_pos
|
int
|
The starting X coordinate (anchor point) of the container. |
required |
y_pos
|
int
|
The starting Y coordinate (anchor point) of the container. |
required |
spacing
|
int
|
The number of pixels inserted horizontally between each child element. |
15
|
align
|
Align
|
The alignment method that objects in the container will inherit. |
LEFT_TOP
|
common_width
|
int
|
Forces a uniform width for all DIRECT children (e.g., Buttons) added to this specific container. Does not affect deeply nested elements. |
None
|
common_height
|
int
|
Forces a uniform height for all DIRECT children added to this specific container. Does not affect deeply nested elements. |
None
|
style
|
UIStyle
|
The UIStyle object dictating the container's appearance (e.g., background, padding). Inheritable properties provided here will cascade to all children. |
None
|
Example
Creating a horizontal set of three buttons:
import FluxRender as fr
# [Inicialize the scene and coordinate system]
# Define the container for the buttons
horizontal_container = fr.HBox(10, 80, common_height=40, common_width=290)
# Create a function called by buttons
def print_name(button):
print(f"Button pressed: {button.text}")
# Create buttons
button1 = fr.Button("Orange", print_name)
button2 = fr.Button("Blue", print_name)
button3 = fr.Button("Green", print_name)
# Add buttons to the container
horizontal_container.add(button1, button2, button3)
# Add the container to the scene
scene.add(horizontal_container)
Source code in FluxRender/ui.py
FluxRender.colors.ColorMapper
ColorMapper(min_hue: int = 240, max_hue: int = 0, min_saturation: float = 0.4, max_saturation: float = 1.0, min_lightness: float = 0.3, max_lightness: float = 0.65, min_alpha: float = 0.8, max_alpha: float = 1.0, scale_type: ScaleType = ScaleType.LINEAR, scale_function=None, min_value: float = None, max_value: float = None)
A dynamic color interpolation engine that translates scalar fields into vibrant visual gradients.
The ColorMapper acts as the visual translator for the mathematical engine. It takes raw scalar values (such as velocity magnitude, divergence, or custom topological metrics) and smoothly maps them to physical RGBA colors.
Crucially, all color interpolation is performed natively within the HSL (Hue, Saturation, Lightness) color space rather than RGB. This architectural choice guarantees perceptually uniform, vivid transitions and completely eliminates the "muddy" or desaturated mid-tones commonly seen in standard linear color blending. It features highly flexible normalization, allowing bounds to be strictly locked at initialization or dynamically injected frame-by-frame by the rendering entities (like VectorField or ParticleSystem).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
min_hue
|
int
|
Minimum hue in degrees (0-360). Default is 240 (blue). |
240
|
max_hue
|
int
|
Maximum hue in degrees (0-360). Default is 0 (red). |
0
|
min_saturation
|
float
|
Minimum saturation (0-1). Default is 0.4. |
0.4
|
max_saturation
|
float
|
Maximum saturation (0-1). Default is 1.0. |
1.0
|
min_lightness
|
float
|
Minimum lightness (0-1). Default is 0.3. |
0.3
|
max_lightness
|
float
|
Maximum lightness (0-1). Default is 0.65. |
0.65
|
min_alpha
|
float
|
Minimum alpha (0-1). Default is 0.8. |
0.8
|
max_alpha
|
float
|
Maximum alpha (0-1). Default is 1.0. |
1.0
|
scale_type
|
ScaleType
|
The type of scaling to apply to the input values. Default is ScaleType.LINEAR. |
LINEAR
|
scale_function
|
Callable
|
A custom single-argument function f(t). Input t is normalized in [0.0, 1.0], and the output must also be within [0.0, 1.0]. Used only if |
None
|
min_value
|
float
|
Hardcoded minimum value for normalization. If None, the rendering entity will dynamically calculate and inject the minimum value of the current frame. |
None
|
max_value
|
float
|
Hardcoded maximum value for normalization. If None, the rendering entity will dynamically calculate and inject the maximum value. |
None
|
Example
Creating a highly saturated thermal gradient (Blue to Red) with a custom logarithmic-like curve:
import FluxRender as fr
# [Initialize scene and coordinate system here]
# This mapper transitions from green to orange, but uses a square-root curve
mapper = fr.ColorMapper(
min_hue=150,
max_hue=20,
min_saturation=0.8,
max_saturation=1,
min_lightness=0.1,
max_lightness=0.6,
min_alpha=1,
scale_type = fr.ScaleType.CUSTOM,
scale_function = lambda x: x ** 0.5,
)
# Apply the mapper directly to a ParticleSystem
particles = fr.ParticleSystem(
vec_function = lambda x, y: (np.sin(x), np.cos(x) * np.sin(y)),
color_mapper = mapper,
)
scene.add(particles)
Source code in FluxRender/colors.py
calc_color
Maps a scalar value to an RGBA color using HSL color space.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
float
|
The scalar value to map. |
required |
min_value
|
float
|
The minimum value of the range (if self.min_value is not None, it will be used). |
None
|
max_value
|
float
|
The maximum value of the range (if self.max_value is not None, it will be used). |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
color |
tuple
|
A tuple representing the RGBA color (r, g, b, a). |
Source code in FluxRender/colors.py
map_array
Maps a NumPy array of scalar values to an array of RGBA colors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
ndarray
|
A NumPy array of scalar values. |
required |
min_value
|
float
|
The minimum value of the range. |
None
|
max_value
|
float
|
The maximum value of the range. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
colors |
ndarray
|
A NumPy array of RGBA colors corresponding to the input values. |