pytermgui.widgets.pixel_matrix
The module containing all the widgets that can be used to display pixel-based data.
1""" 2The module containing all the widgets that can be used to display 3pixel-based data. 4""" 5 6from __future__ import annotations 7 8from ..ansi_interface import MouseEvent 9from ..markup import tim 10from ..regex import real_length 11from .base import Widget 12 13__all__ = [ 14 "PixelMatrix", 15 "DensePixelMatrix", 16] 17 18 19class PixelMatrix(Widget): 20 """A matrix of pixels. 21 22 The way this object should be used is by accessing & modifying 23 the underlying matrix. This can be done using the set & getitem 24 syntacies: 25 26 ```python3 27 from pytermgui import PixelMatrix 28 29 matrix = PixelMatrix(10, 10, default="white") 30 for y in matrix.rows: 31 for x in matrix.columns: 32 matrix[y, x] = "black" 33 ``` 34 35 The above snippet draws a black diagonal going from the top left 36 to bottom right. 37 38 Each item of the rows should be a single PyTermGUI-parsable color 39 string. For more information about this, see 40 `pytermgui.ansi_interface.Color`. 41 """ 42 43 selected_pixel: tuple[tuple[int, int], str] | None 44 """A tuple of the position & value (color) of the currently hovered pixel.""" 45 46 def __init__(self, width: int, height: int, default: str = "", **attrs) -> None: 47 """Initializes a PixelMatrix. 48 49 Args: 50 width: The amount of columns the matrix will have. 51 height: The amount of rows the matrix will have. 52 default: The default color to use to initialize the matrix with. 53 """ 54 55 super().__init__(**attrs) 56 57 self.rows = height 58 self.columns = width 59 60 self._matrix = [] 61 62 for _ in range(self.rows): 63 self._matrix.append([default] * self.columns) 64 65 self.selected_pixel = None 66 self.build() 67 68 @classmethod 69 def from_matrix(cls, matrix: list[list[str]]) -> PixelMatrix: 70 """Creates a PixelMatrix from the given matrix. 71 72 The given matrix should be a list of rows, each containing a number 73 of cells. It is optimal for all rows to share the same amount of cells. 74 75 Args: 76 matrix: The matrix to use. This is a list of lists of strings 77 with each element representing a PyTermGUI-parseable color. 78 79 Returns: 80 A new type(self). 81 """ 82 83 obj = cls(max(len(row) for row in matrix), len(matrix)) 84 setattr(obj, "_matrix", matrix) 85 obj.build() 86 87 return obj 88 89 def _update_dimensions(self, lines: list[str]): 90 """Updates the dimensions of this matrix. 91 92 Args: 93 lines: A list of lines that the calculations will be based upon. 94 """ 95 96 self.static_width = max(real_length(line) for line in lines) 97 self.height = len(lines) 98 99 def on_hover(self, event: MouseEvent) -> bool: 100 """Sets `selected_pixel` to the current pixel.""" 101 102 xoffset = event.position[0] - self.pos[0] 103 yoffset = event.position[1] - self.pos[1] 104 105 color = self._matrix[yoffset][xoffset // 2] 106 107 self.selected_pixel = ((xoffset // 2, yoffset), color) 108 return True 109 110 def get_lines(self) -> list[str]: 111 """Returns lines built by the `build` method.""" 112 113 return self._lines 114 115 def build(self) -> list[str]: 116 """Builds the image pixels. 117 118 Returns: 119 The lines that this object will return, until a subsequent `build` call. 120 These lines are stored in the `self._lines` variable. 121 """ 122 123 lines: list[str] = [] 124 for row in self._matrix: 125 line = "" 126 for pixel in row: 127 if len(pixel) > 0: 128 line += f"[@{pixel}] " 129 else: 130 line += "[/] " 131 132 lines.append(tim.parse(line)) 133 134 self._lines = lines 135 self._update_dimensions(lines) 136 137 return lines 138 139 def __getitem__(self, indices: tuple[int, int]) -> str: 140 """Gets a matrix item.""" 141 142 posy, posx = indices 143 return self._matrix[posy][posx] 144 145 def __setitem__(self, indices: tuple[int, int], value: str) -> None: 146 """Sets a matrix item.""" 147 148 posy, posx = indices 149 self._matrix[posy][posx] = value 150 151 152class DensePixelMatrix(PixelMatrix): 153 """A more dense (2x) PixelMatrix. 154 155 Due to each pixel only occupying 1/2 characters in height, accurately 156 determining selected_pixel is impossible, thus the functionality does 157 not exist here. 158 """ 159 160 def __init__(self, width: int, height: int, default: str = "", **attrs) -> None: 161 """Initializes DensePixelMatrix. 162 163 Args: 164 width: The width of the matrix. 165 height: The height of the matrix. 166 default: The default color to use to initialize the matrix with. 167 """ 168 169 super().__init__(width, height, default, **attrs) 170 171 self.width = width // 2 172 173 def handle_mouse(self, event: MouseEvent) -> bool: 174 """As mentioned in the class documentation, mouse handling is disabled here.""" 175 176 return False 177 178 def build(self) -> list[str]: 179 """Builds the image pixels, using half-block characters. 180 181 Returns: 182 The lines that this object will return, until a subsequent `build` call. 183 These lines are stored in the `self._lines` variable. 184 """ 185 186 lines = [] 187 lines_to_zip: list[list[str]] = [] 188 for row in self._matrix: 189 lines_to_zip.append(row) 190 if len(lines_to_zip) != 2: 191 continue 192 193 line = "" 194 top_row, bottom_row = lines_to_zip[0], lines_to_zip[1] 195 for bottom, top in zip(bottom_row, top_row): 196 if len(top) + len(bottom) == 0: 197 line += " " 198 continue 199 200 if bottom == "": 201 line += tim.parse(f"[{top}]▀") 202 continue 203 204 markup_str = "@" + top + " " if len(top) > 0 else "" 205 206 markup_str += bottom 207 line += tim.parse(f"[{markup_str}]▄") 208 209 lines.append(line) 210 lines_to_zip = [] 211 212 self._lines = lines 213 self._update_dimensions(lines) 214 215 return lines
20class PixelMatrix(Widget): 21 """A matrix of pixels. 22 23 The way this object should be used is by accessing & modifying 24 the underlying matrix. This can be done using the set & getitem 25 syntacies: 26 27 ```python3 28 from pytermgui import PixelMatrix 29 30 matrix = PixelMatrix(10, 10, default="white") 31 for y in matrix.rows: 32 for x in matrix.columns: 33 matrix[y, x] = "black" 34 ``` 35 36 The above snippet draws a black diagonal going from the top left 37 to bottom right. 38 39 Each item of the rows should be a single PyTermGUI-parsable color 40 string. For more information about this, see 41 `pytermgui.ansi_interface.Color`. 42 """ 43 44 selected_pixel: tuple[tuple[int, int], str] | None 45 """A tuple of the position & value (color) of the currently hovered pixel.""" 46 47 def __init__(self, width: int, height: int, default: str = "", **attrs) -> None: 48 """Initializes a PixelMatrix. 49 50 Args: 51 width: The amount of columns the matrix will have. 52 height: The amount of rows the matrix will have. 53 default: The default color to use to initialize the matrix with. 54 """ 55 56 super().__init__(**attrs) 57 58 self.rows = height 59 self.columns = width 60 61 self._matrix = [] 62 63 for _ in range(self.rows): 64 self._matrix.append([default] * self.columns) 65 66 self.selected_pixel = None 67 self.build() 68 69 @classmethod 70 def from_matrix(cls, matrix: list[list[str]]) -> PixelMatrix: 71 """Creates a PixelMatrix from the given matrix. 72 73 The given matrix should be a list of rows, each containing a number 74 of cells. It is optimal for all rows to share the same amount of cells. 75 76 Args: 77 matrix: The matrix to use. This is a list of lists of strings 78 with each element representing a PyTermGUI-parseable color. 79 80 Returns: 81 A new type(self). 82 """ 83 84 obj = cls(max(len(row) for row in matrix), len(matrix)) 85 setattr(obj, "_matrix", matrix) 86 obj.build() 87 88 return obj 89 90 def _update_dimensions(self, lines: list[str]): 91 """Updates the dimensions of this matrix. 92 93 Args: 94 lines: A list of lines that the calculations will be based upon. 95 """ 96 97 self.static_width = max(real_length(line) for line in lines) 98 self.height = len(lines) 99 100 def on_hover(self, event: MouseEvent) -> bool: 101 """Sets `selected_pixel` to the current pixel.""" 102 103 xoffset = event.position[0] - self.pos[0] 104 yoffset = event.position[1] - self.pos[1] 105 106 color = self._matrix[yoffset][xoffset // 2] 107 108 self.selected_pixel = ((xoffset // 2, yoffset), color) 109 return True 110 111 def get_lines(self) -> list[str]: 112 """Returns lines built by the `build` method.""" 113 114 return self._lines 115 116 def build(self) -> list[str]: 117 """Builds the image pixels. 118 119 Returns: 120 The lines that this object will return, until a subsequent `build` call. 121 These lines are stored in the `self._lines` variable. 122 """ 123 124 lines: list[str] = [] 125 for row in self._matrix: 126 line = "" 127 for pixel in row: 128 if len(pixel) > 0: 129 line += f"[@{pixel}] " 130 else: 131 line += "[/] " 132 133 lines.append(tim.parse(line)) 134 135 self._lines = lines 136 self._update_dimensions(lines) 137 138 return lines 139 140 def __getitem__(self, indices: tuple[int, int]) -> str: 141 """Gets a matrix item.""" 142 143 posy, posx = indices 144 return self._matrix[posy][posx] 145 146 def __setitem__(self, indices: tuple[int, int], value: str) -> None: 147 """Sets a matrix item.""" 148 149 posy, posx = indices 150 self._matrix[posy][posx] = value
A matrix of pixels.
The way this object should be used is by accessing & modifying the underlying matrix. This can be done using the set & getitem syntacies:
from pytermgui import PixelMatrix
matrix = PixelMatrix(10, 10, default="white")
for y in matrix.rows:
for x in matrix.columns:
matrix[y, x] = "black"
The above snippet draws a black diagonal going from the top left to bottom right.
Each item of the rows should be a single PyTermGUI-parsable color
string. For more information about this, see
pytermgui.ansi_interface.Color
.
47 def __init__(self, width: int, height: int, default: str = "", **attrs) -> None: 48 """Initializes a PixelMatrix. 49 50 Args: 51 width: The amount of columns the matrix will have. 52 height: The amount of rows the matrix will have. 53 default: The default color to use to initialize the matrix with. 54 """ 55 56 super().__init__(**attrs) 57 58 self.rows = height 59 self.columns = width 60 61 self._matrix = [] 62 63 for _ in range(self.rows): 64 self._matrix.append([default] * self.columns) 65 66 self.selected_pixel = None 67 self.build()
Initializes a PixelMatrix.
Args
- width: The amount of columns the matrix will have.
- height: The amount of rows the matrix will have.
- default: The default color to use to initialize the matrix with.
A tuple of the position & value (color) of the currently hovered pixel.
69 @classmethod 70 def from_matrix(cls, matrix: list[list[str]]) -> PixelMatrix: 71 """Creates a PixelMatrix from the given matrix. 72 73 The given matrix should be a list of rows, each containing a number 74 of cells. It is optimal for all rows to share the same amount of cells. 75 76 Args: 77 matrix: The matrix to use. This is a list of lists of strings 78 with each element representing a PyTermGUI-parseable color. 79 80 Returns: 81 A new type(self). 82 """ 83 84 obj = cls(max(len(row) for row in matrix), len(matrix)) 85 setattr(obj, "_matrix", matrix) 86 obj.build() 87 88 return obj
Creates a PixelMatrix from the given matrix.
The given matrix should be a list of rows, each containing a number of cells. It is optimal for all rows to share the same amount of cells.
Args
- matrix: The matrix to use. This is a list of lists of strings with each element representing a PyTermGUI-parseable color.
Returns
A new type(self).
100 def on_hover(self, event: MouseEvent) -> bool: 101 """Sets `selected_pixel` to the current pixel.""" 102 103 xoffset = event.position[0] - self.pos[0] 104 yoffset = event.position[1] - self.pos[1] 105 106 color = self._matrix[yoffset][xoffset // 2] 107 108 self.selected_pixel = ((xoffset // 2, yoffset), color) 109 return True
Sets selected_pixel
to the current pixel.
111 def get_lines(self) -> list[str]: 112 """Returns lines built by the `build` method.""" 113 114 return self._lines
Returns lines built by the build
method.
116 def build(self) -> list[str]: 117 """Builds the image pixels. 118 119 Returns: 120 The lines that this object will return, until a subsequent `build` call. 121 These lines are stored in the `self._lines` variable. 122 """ 123 124 lines: list[str] = [] 125 for row in self._matrix: 126 line = "" 127 for pixel in row: 128 if len(pixel) > 0: 129 line += f"[@{pixel}] " 130 else: 131 line += "[/] " 132 133 lines.append(tim.parse(line)) 134 135 self._lines = lines 136 self._update_dimensions(lines) 137 138 return lines
Builds the image pixels.
Returns
The lines that this object will return, until a subsequent
build
call. These lines are stored in theself._lines
variable.
Inherited Members
- pytermgui.widgets.base.Widget
- set_style
- set_char
- styles
- chars
- keys
- serialized
- is_bindable
- size_policy
- parent_align
- from_data
- bindings
- id
- selectables_length
- selectables
- is_selectable
- static_width
- relative_width
- terminal
- get_change
- contains
- handle_mouse
- handle_key
- serialize
- copy
- bind
- unbind
- execute_binding
- select
- debug
153class DensePixelMatrix(PixelMatrix): 154 """A more dense (2x) PixelMatrix. 155 156 Due to each pixel only occupying 1/2 characters in height, accurately 157 determining selected_pixel is impossible, thus the functionality does 158 not exist here. 159 """ 160 161 def __init__(self, width: int, height: int, default: str = "", **attrs) -> None: 162 """Initializes DensePixelMatrix. 163 164 Args: 165 width: The width of the matrix. 166 height: The height of the matrix. 167 default: The default color to use to initialize the matrix with. 168 """ 169 170 super().__init__(width, height, default, **attrs) 171 172 self.width = width // 2 173 174 def handle_mouse(self, event: MouseEvent) -> bool: 175 """As mentioned in the class documentation, mouse handling is disabled here.""" 176 177 return False 178 179 def build(self) -> list[str]: 180 """Builds the image pixels, using half-block characters. 181 182 Returns: 183 The lines that this object will return, until a subsequent `build` call. 184 These lines are stored in the `self._lines` variable. 185 """ 186 187 lines = [] 188 lines_to_zip: list[list[str]] = [] 189 for row in self._matrix: 190 lines_to_zip.append(row) 191 if len(lines_to_zip) != 2: 192 continue 193 194 line = "" 195 top_row, bottom_row = lines_to_zip[0], lines_to_zip[1] 196 for bottom, top in zip(bottom_row, top_row): 197 if len(top) + len(bottom) == 0: 198 line += " " 199 continue 200 201 if bottom == "": 202 line += tim.parse(f"[{top}]▀") 203 continue 204 205 markup_str = "@" + top + " " if len(top) > 0 else "" 206 207 markup_str += bottom 208 line += tim.parse(f"[{markup_str}]▄") 209 210 lines.append(line) 211 lines_to_zip = [] 212 213 self._lines = lines 214 self._update_dimensions(lines) 215 216 return lines
A more dense (2x) PixelMatrix.
Due to each pixel only occupying 1/2 characters in height, accurately determining selected_pixel is impossible, thus the functionality does not exist here.
161 def __init__(self, width: int, height: int, default: str = "", **attrs) -> None: 162 """Initializes DensePixelMatrix. 163 164 Args: 165 width: The width of the matrix. 166 height: The height of the matrix. 167 default: The default color to use to initialize the matrix with. 168 """ 169 170 super().__init__(width, height, default, **attrs) 171 172 self.width = width // 2
Initializes DensePixelMatrix.
Args
- width: The width of the matrix.
- height: The height of the matrix.
- default: The default color to use to initialize the matrix with.
174 def handle_mouse(self, event: MouseEvent) -> bool: 175 """As mentioned in the class documentation, mouse handling is disabled here.""" 176 177 return False
As mentioned in the class documentation, mouse handling is disabled here.
179 def build(self) -> list[str]: 180 """Builds the image pixels, using half-block characters. 181 182 Returns: 183 The lines that this object will return, until a subsequent `build` call. 184 These lines are stored in the `self._lines` variable. 185 """ 186 187 lines = [] 188 lines_to_zip: list[list[str]] = [] 189 for row in self._matrix: 190 lines_to_zip.append(row) 191 if len(lines_to_zip) != 2: 192 continue 193 194 line = "" 195 top_row, bottom_row = lines_to_zip[0], lines_to_zip[1] 196 for bottom, top in zip(bottom_row, top_row): 197 if len(top) + len(bottom) == 0: 198 line += " " 199 continue 200 201 if bottom == "": 202 line += tim.parse(f"[{top}]▀") 203 continue 204 205 markup_str = "@" + top + " " if len(top) > 0 else "" 206 207 markup_str += bottom 208 line += tim.parse(f"[{markup_str}]▄") 209 210 lines.append(line) 211 lines_to_zip = [] 212 213 self._lines = lines 214 self._update_dimensions(lines) 215 216 return lines
Builds the image pixels, using half-block characters.
Returns
The lines that this object will return, until a subsequent
build
call. These lines are stored in theself._lines
variable.
Inherited Members
- pytermgui.widgets.base.Widget
- set_style
- set_char
- styles
- chars
- keys
- serialized
- is_bindable
- size_policy
- parent_align
- from_data
- bindings
- id
- selectables_length
- selectables
- is_selectable
- static_width
- relative_width
- terminal
- get_change
- contains
- handle_key
- serialize
- copy
- bind
- unbind
- execute_binding
- select
- debug