Source code for lightningchart.ui.text_box

from __future__ import annotations
import uuid

try:
    from typing import Unpack
except ImportError:
    from typing_extensions import Unpack

from lightningchart.ui import UIEWithPosition, UIElement, UIElementsWithAutoDispose
from lightningchart.utils import convert_to_base64, convert_color_to_hex
from lightningchart.utils.utils import ColorInput, PaddingKwargs


[docs] class TextBox(UIEWithPosition, UIElementsWithAutoDispose): """UI Element for adding text annotations on top of the chart.""" def __init__( self, chart, text: str = None, x: int = None, y: int = None, position_scale: str = 'axis', ): UIElement.__init__(self, chart) self.instance.send( self.id, 'textBox', {'chart': self.chart.id, 'positionScale': position_scale}, ) if text: self.set_text(text) if x is not None and y is not None: self.set_position(x, y)
[docs] def set_text(self, text: str): """Set the content of the text box. Args: text (str): Text string. Returns: The instance of the class for fluent interface. """ self.instance.send(self.id, 'setText', {'text': text}) return self
[docs] def set_padding(self, *args, **kwargs: Unpack[PaddingKwargs]): """Set padding around object in pixels. Args: *args: A single numeric value (int or float) for uniform padding on all sides. **kwargs: Optional named arguments to specify padding for individual sides: - `left` (int or float): Padding for the left side. - `right` (int or float): Padding for the right side. - `top` (int or float): Padding for the top side. - `bottom` (int or float): Padding for the bottom side. Examples: - `set_padding(5)`: Sets uniform padding for all sides (integer or float). - `set_padding(left=10, top=15)`: Sets padding for specific sides only. - `set_padding(left=10, top=15, right=20, bottom=25)`: Fully define padding for all sides. Returns: The instance of the class for fluent interface. """ if len(args) == 1 and isinstance(args[0], (int, float)): padding = args[0] elif kwargs: padding = {} for key in ['left', 'right', 'bottom', 'top']: if key in kwargs: padding[key] = kwargs[key] else: raise ValueError( 'Invalid arguments. Use one of the following formats:\n' '- set_padding(5): Uniform padding for all sides.\n' '- set_padding(left=10, top=15): Specify individual sides.\n' '- set_padding(left=10, top=15, right=20, bottom=25): Full padding definition.' ) self.instance.send(self.id, 'setPadding', {'padding': padding}) return self
[docs] def set_text_fill_style(self, color: ColorInput | None): """Set the color of the text. Args: color (Color): Color of the text. Use 'transparent' or None to hide. Returns: The instance of the class for fluent interface. """ color = convert_color_to_hex(color) if color is not None else None self.instance.send(self.id, 'setTextFillStyle', {'color': color}) return self
[docs] def set_text_font( self, size: int | float, family: str = 'Segoe UI, -apple-system, Verdana, Helvetica', style: str = 'normal', weight: str = 'normal', ): """Set the font style of the text. Args: size (int | float): CSS font size. For example, 16. family (str): CSS font family. For example, 'Arial, Helvetica, sans-serif'. weight (str): CSS font weight. For example, 'bold'. style (str): CSS font style. For example, 'italic' Returns: The instance of the class for fluent interface. """ self.instance.send( self.id, 'setTextFont', {'family': family, 'size': size, 'weight': weight, 'style': style}, ) return self
[docs] def set_text_rotation(self, rotation: int | float): """Set the rotation of the text. Args: rotation (int | float): Rotation in degrees. Returns: The instance of the class for fluent interface. """ self.instance.send(self.id, 'setTextRotation', {'rotation': rotation}) return self
[docs] def set_background_color(self, color: ColorInput | None): """Set the background color of the text box. Args: color (Color): Color of the background. Use 'transparent' or None to hide. Returns: The instance of the class for fluent interface. """ color = convert_color_to_hex(color) if color is not None else None self.instance.send(self.id, 'setBackgroundFill', {'color': color}) return self
[docs] def set_stroke(self, thickness: int | float, color: ColorInput | None = None): """Set the text box stroke style. Args: thickness (int | float): Thickness of the stroke. color (Color): Color of the stroke. Use 'transparent' or None to hide. Returns: The instance of the class for fluent interface. """ color = convert_color_to_hex(color) if color is not None else None self.instance.send( self.id, 'setBackgroundStroke', {'thickness': thickness, 'color': color}, ) return self
[docs] def add_video( self, video_source: str, fit_mode: str = 'fit', size: dict = None, ): """ Updates the background of the current TextBox UI element to use a video (provided as a Base64-encoded data URI) as its fill. Args: video_source (str): Path to the video file (MP4 or WEBM) or URL. fit_mode (str): How the video should fit ('Fit', 'Stretch', 'Fill', 'Tile', 'Center'). size (dict, optional): Desired size of the video display, e.g. {"width": 150, "height": 150}. This controls the UI element's padding. Defaults to 100x100. Returns: self: The instance for fluent interfacing. Example: >>> textbox.add_video("D:/path/to/local_video.mp4") >>> textbox.add_video("https://example.com/video.mp4") """ if not video_source: raise ValueError('Video source is required.') video_data_uri = convert_to_base64(video_source) args = { 'videoSource': video_data_uri, 'fitMode': fit_mode, 'size': size or {'width': 100, 'height': 100}, } for fit_mode_option in [ 'Fit', 'Stretch', 'Fill', 'Tile', 'Center', ]: if fit_mode.lower() == fit_mode_option.lower(): args['fitMode'] = fit_mode_option break self.instance.send(self.id, 'addCustomVideo', args) return self
[docs] def add_image( self, source: str, fit_mode: str = 'Stretch', size: dict = None, ): """ Updates the background of the current TextBox UI element to use an image (provided as a Base64-encoded data URI) as its fill. Args: source (str): Path to the image file or URL. fit_mode (str): How the image should fit ('Stretch', 'Fill', 'Fit', 'Tile', 'Center'). size (dict, optional): Desired size of the image display, e.g. {"width": 100, "height": 100}. Defaults to 100x100. Returns: self: The instance for fluent interfacing. Example: >>> textbox.add_image("D:/path/to/local_image.png") >>> textbox.add_image("https://example.com/image.jpg") """ if not source: raise ValueError('Image source is required.') image_data_uri = convert_to_base64(source) args = { 'source': image_data_uri, 'fitMode': fit_mode, 'size': size or {'width': 100, 'height': 100}, } for fit_mode_option in [ 'Stretch', 'Fill', 'Fit', 'Tile', 'Center', ]: if fit_mode.lower() == fit_mode_option.lower(): args['fitMode'] = fit_mode_option break self.instance.send(self.id, 'addCustomImage', args) return self
[docs] def set_effect(self, enabled: bool): """Set theme effect enabled on component or disabled. Args: enabled: Boolean flag. Returns: The instance of the class for fluent interface. """ self.instance.send(self.id, 'setEffect', {'enabled': enabled}) return self
[docs] def add_event_listener( self, event: str, handler: callable | None = None, throttle_ms: int = 0, once: bool = False, ) -> str: """Attach an event listener to the TextBox. Args: event: Event name, e.g. 'pointerdown', 'pointermove', 'click'. handler: Optional Python callback that receives the event payload. throttle_ms: Minimum delay between handler invocations. once: When True, the listener removes itself after the first trigger. Returns: The callback id that identifies this listener. """ callback_id = str(uuid.uuid4()).split('-')[0] if handler else '' if handler is not None: self.instance.event_handlers[callback_id] = handler self.instance.send( self.id, 'addEventListener', { 'event': event, 'callbackId': callback_id or None, 'throttleMs': int(throttle_ms) if throttle_ms else 0, 'options': {'once': bool(once)}, }, ) return callback_id
[docs] def get_text(self) -> str | None: """Get the text content of the text box. Returns: str | None: The text content of the text box. """ return self.instance.get(self.id, 'textBoxGetText', {})
[docs] def get_text_font(self) -> dict | None: """Get font settings of the text box. Returns: dict | None: Font settings with keys: - size (float): Font size - family (str): Font family - weight (str): Font weight - style (str): Font style """ return self.instance.get(self.id, 'textBoxGetTextFont', {})
[docs] def get_text_rotation(self) -> float | None: """Get the rotation of the text in degrees. Returns: float | None: Rotation in degrees. """ return self.instance.get(self.id, 'textBoxGetTextRotation', {})
[docs] def get_text_fill_style(self) -> str | None: """Get the text fill style (color). Returns: str | None: Color as rgba string. """ return self.instance.get(self.id, 'textBoxGetTextFillStyle', {})
[docs] def get_padding(self) -> dict | None: """Get padding around the text box in pixels. Returns: dict | None: Margin datastructure with padding values. """ return self.instance.get(self.id, 'textBoxGetPadding', {})
[docs] def get_margin(self) -> dict | None: """Get margin around the text box in pixels. Returns: dict | None: Margin datastructure with margin values. """ return self.instance.get(self.id, 'textBoxGetMargin', {})
[docs] def get_background(self) -> dict | None: """Get the text box background styling. Returns: dict | None: Contains `type`, `fill_style`, and `stroke_style`. """ return self.instance.get(self.id, 'textBoxGetBackground', {})
[docs] def get_effect(self) -> bool | None: """Get theme effect enabled state on the text box. Returns: bool | None: True if theme effect is enabled, False otherwise. """ return self.instance.get(self.id, 'textBoxGetEffect', {})
[docs] def get_highlight(self) -> float | None: """Get state of component highlighting. Returns: float | None: Number between 0 and 1, where 1 is fully highlighted. """ return self.instance.get(self.id, 'textBoxGetHighlight', {})
[docs] def get_pointer_events(self) -> bool | None: """Get the mouse interactions state. Returns: bool | None: Mouse interactions state. """ return self.instance.get(self.id, 'textBoxGetPointerEvents', {})
[docs] def is_disposed(self) -> bool | None: """Check whether the text box is disposed. Returns: bool | None: True if object is disposed. """ return self.instance.get(self.id, 'textBoxIsDisposed', {})
[docs] class PointableTextBox(TextBox): """Interactive TextBox variant with built-in pointer support and drag handles.""" def __init__( self, chart, text: str = None, x: int = None, y: int = None, position_scale: str = 'axis', ): UIElement.__init__(self, chart) self.instance.send( self.id, 'pointableTextBox', {'chart': self.chart.id, 'positionScale': position_scale}, ) if text: self.set_text(text) if x is not None and y is not None: self.set_position(x, y)
[docs] def set_direction(self, direction: str): """Set pointable direction.""" direction_map = { 'up': 0, 'right': 1, 'down': 2, 'left': 3, } value = direction if isinstance(direction, str): value = direction_map.get(direction.lower(), direction) self.instance.send(self.id, 'pointableTextBoxSetDirection', {'direction': value}) return self
[docs] def get_direction(self): """Get current pointable direction.""" return self.instance.get(self.id, 'pointableTextBoxGetDirection', {})
[docs] def set_pointer_length(self, length: int | float): """Set pointer head length in pixels.""" self.instance.send(self.id, 'pointableTextBoxSetPointerLength', {'length': length}) return self
[docs] def get_pointer_length(self) -> float | None: """Get pointer head length in pixels.""" return self.instance.get(self.id, 'pointableTextBoxGetPointerLength', {})
[docs] def set_tick_label_padding(self, padding: int | float): """Set padding between pointer and label.""" self.instance.send(self.id, 'pointableTextBoxSetTickLabelPadding', {'padding': padding}) return self
[docs] def get_tick_label_padding(self) -> float | None: """Get padding between pointer and label.""" return self.instance.get(self.id, 'pointableTextBoxGetTickLabelPadding', {})