xnano.placement
xnano.placement
¶
xnano.placement
A buffer placed on a canvas, with a position and size that are formulas.
Classes:
-
Placement–A buffer placed on a canvas, with a position and size that are formulas.
Placement
¶
Placement(canvas: Canvas[DepsT, StateT], buffer: Buffer, parent_buffer: Buffer | None = None, parent_owner: Canvas[object, object] | Placement[object, object] | None = None)
Bases: _Hooked[DepsT, StateT], _TextModifiers
A buffer placed on a canvas, with a position and size that are formulas.
Assign any of x, y, width and height an Axis:
a number, a percentage of the parent, or an expression. Numbers apply at once;
everything else is evaluated again before every frame, so a placement can follow the
clock, the canvas's size or another buffer without a callback.
Assigning a range instead ((0, 20)) limits the axis rather than setting it.
For x and y the range is how far the placement may travel, so a slider's thumb
is a placement whose x is limited to its track; whatever is assigned to it later,
by a drag hook, is held inside the track.
For width and height it is the smallest and largest size.
Percentages and ranges only change when something about the canvas does, so they cost nothing while it is still. An expression is assumed to change with time, so a canvas with one keeps drawing every frame; use a percentage for a layout that only follows the size of the canvas.
Get one from Canvas.write or nest a child placement inside
another with Placement.write.
Attributes:
-
core_buffer(Buffer) –The core buffer that is placed.
-
canvas(Canvas[DepsT, StateT]) –The canvas the buffer is placed on.
-
parent(ParentExpressionScope) –Symbolic expressions for the parent container's
width,heightandsize. -
root(RootExpressionScope) –Symbolic expressions for the root canvas's
width,height,sizeandtime. -
time(NumericValue) –Symbolic expression for elapsed seconds on the canvas clock.
-
x(int) –The column of the left edge, relative to the parent.
-
y(int) –The row of the top edge, relative to the parent.
-
width(int) –The width in cells.
-
height(int) –The height in cells.
-
layer(int) –Placements with a higher layer are drawn over those with a lower one.
-
is_visible(bool) –Whether the buffer is drawn.
-
text(str) –The text shown, line by line.
Examples:
import xnano
with xnano.new(width=20, height=3) as canvas:
label = canvas.write('hi')
label.x = (label.parent.width - label.width) // 2
assert label.x == 9
thumb = canvas.write('#', x=(2, 10))
thumb.x = 40
assert thumb.x == 10
thumb.x = 0
assert thumb.x == 2
Place a buffer on a canvas. Get one from canvas.write instead of calling this.
Parameters:
-
canvas(Canvas[DepsT, StateT]) –The canvas the buffer is placed on.
-
buffer(Buffer) –The buffer that is placed.
-
parent_buffer(Buffer | None, default:None) –The parent buffer
bufferis attached to (defaults tocanvas.core_buffer). -
parent_owner(Canvas[object, object] | Placement[object, object] | None, default:None) –The placement or canvas that owns
parent_buffer(defaults tocanvas).
- API Reference xnano
Methods:
-
local–Convert a cell of the screen into a cell of this placement.
-
move–Move the placement by a number of cells along each axis.
-
up–Move the placement up by
countrows; seemove. -
down–Move the placement down by
countrows; seemove. -
left–Move the placement left by
countcolumns; seemove. -
right–Move the placement right by
countcolumns; seemove. -
render–Draw the placement, with its border, padding and nested placements, to a string.
-
refresh–Draw a placement made from a component again, at the next frame.
-
write–Add a child placement inside this placement.
-
update–Change this placement's content with operations, styles or effects.
-
__or__–Apply
operationto this placement and returnself. -
__ior__–Apply
operationto this placement in place and returnself. -
remove–Take the buffer off the canvas. Removing twice is harmless.
-
__setattr__–Set an attribute, or raise
AttributeErrorfor an unknown public name. -
bold–Make the text bold, or undo it with
False; the same as settingis_bold. -
dim–Dim the text, or undo it with
False; the same as settingis_dim. -
italic–Make the text italic, or undo it with
False; the same as settingis_italic. -
underline–Underline the text, or undo it with
False; the same as settingis_underlined. -
blink–Make the text blink, or undo it with
False; the same as settingis_blinking. -
reverse–Swap the foreground and background, or undo it with
False; the same as settingis_reversed. -
hidden–Hide the text, or undo it with
False; the same as settingis_hidden. -
crossed_out–Strike the text through, or undo it with
False; the same as settingis_crossed_out. -
hook–Call a function when something happens on this canvas or placement.
Source code in xnano/placement.py
core_buffer
property
¶
core_buffer: Buffer
The core buffer of the content, which core operations and widgets draw into.
A placement with a border, padding or margin around content that is not plain text draws that decoration in a buffer of its own; this is the buffer inside it.
state
property
¶
state: StateNamespace
State that belongs to this placement, read with get and written with push.
It is the state of one placement, separate from the canvas's own
(Canvas.state) and from that of other placements, and
it is deleted when the placement is removed. Asking a removed placement for its state
raises a TerminalClosedError, so finish with the
state before calling remove. See StateNamespace for the
path rules.
Examples:
parent
property
¶
parent: ParentExpressionScope
Symbolic expressions for the parent container's width, height and size.
root
property
¶
root: RootExpressionScope
Symbolic expressions for the root canvas's width, height, size and time.
layer
property
writable
¶
layer: int
Placements with a higher layer are drawn over those with a lower one.
edges
property
writable
¶
edges: EdgeBehavior
What this content does at the edges of its area: 'clip', 'stop' or 'wrap'.
Its area is what it is written on: the canvas, the placement around it, or its slot
on a canvas with a 'column' or 'row' layout. Content written on the outer
canvas inside the with block of a canvas created in it lives in that canvas's
area, and follows that canvas's edges. 'clip' lets it move past an
edge, where it is not drawn. 'stop' holds it inside the area whenever it moves
or is assigned a position, so a moved piece stops at the edge; a range given for
x or y takes the place of the area's edges on that axis. 'wrap' continues
text on the next rows of the area, wrapped again whenever the area's width changes;
on content that is not text it is the same as 'clip'. Assign None to follow
what it is written on again: the setting of the placement around it, or the canvas's
edges.
Raises:
-
ValueError–The value is not
'clip','stop','wrap'orNone.
Examples:
import xnano
with xnano.new(width=10, height=3) as canvas:
ball = canvas.write('o', edges='stop')
ball.right(50).down(50)
assert (ball.x, ball.y) == (9, 2)
note = canvas.write('one two three', edges='wrap')
assert note.text == 'one two three'
assert canvas.render().splitlines()[:2] == ['one two', 'three']
fx
property
¶
The visual effects of this placement, one method for each effect.
placement.fx.fade_to(foreground='red') starts a fade on the placement at once, from
a hook or from anywhere else, and placement.fx.clear() stops what was started here.
See RenderableEffects.
Examples:
import xnano
from xnano.events import Event
with xnano.new(width=20, height=1) as canvas:
content = canvas.write('Press e')
@canvas.hook(on='key')
def flash(context: xnano.Context) -> None:
if context.keyboard.key == 'e':
content.fx.fade_to(foreground='red', duration_milliseconds=200)
canvas.push(Event.key_press('e'))
canvas.step()
assert len(content.fx.active) == 1
region
property
¶
region: Region
The cells of the content as a Region: read and write
placement.region[x, y].
Around text with a border, padding or margin, the region is the area inside them.
Examples:
text
property
writable
¶
text: str
The text shown, line by line.
Assign new text to change what a text placement says; the placement grows or shrinks to fit it, unless its size was set.
style
property
writable
¶
style: Style | None
A ready-made style that the colors and modifiers are applied over.
color
property
¶
color: Colors
border
property
writable
¶
border: BorderAppearance
The border: its kind, a setting for each side, its color and its title.
Assign 'plain', 'rounded', 'double' or 'thick' to draw a border
on every side, True for 'plain' and False to remove it. It works on any
content, not only on text.
The border, padding and margin are drawn around the content, so the placement grows by the cells they take. A widget with no size of its own is shrunk to fit its parent, border included.
Examples:
padding
property
writable
¶
padding: PaddingAppearance
The space between the border and the content, edge by edge.
Assign a number of cells, a percentage such as '10%' or a dictionary such as
{'vertical': 1, 'horizontal': 2}, or set one edge with padding.left = 2.
margin
property
writable
¶
margin: MarginAppearance
The transparent space outside the border, edge by edge, set like padding.
local
¶
Convert a cell of the screen into a cell of this placement.
Parameters:
-
point(Point) –A cell in screen coordinates, such as
context.mouse.position.
Examples:
import xnano
from xnano_core import Point
with xnano.new(width=20, height=4) as canvas:
placement = canvas.write('hi', x=10, y=1)
assert placement.local(Point(11, 1)) == Point(1, 0)
Source code in xnano/placement.py
move
¶
Move the placement by a number of cells along each axis.
The move is held inside a range on the axis
(x=(0, 39)), so a slider's thumb stops at the ends of its track. A position that
is a formula keeps its formula and shifts it. Piping xnano.operations.Move onto
the placement is also held inside its ranges.
Parameters:
-
x(int, default:0) –Columns to move right; a negative number moves left.
-
y(int, default:0) –Rows to move down; a negative number moves up.
Returns:
-
Placement[DepsT, StateT]–The placement, so calls can chain.
Raises:
-
TypeError–An amount is not a whole number.
Examples:
import xnano
with xnano.new(width=20, height=3) as canvas:
thumb = canvas.write('#', x=(0, 10), y=1)
thumb.move(x=4, y=-1)
assert (thumb.x, thumb.y) == (4, 0)
thumb.right(99)
assert thumb.x == 10
Source code in xnano/placement.py
up
¶
Move the placement up by count rows; see move.
Parameters:
-
count(int, default:1) –How many rows to move.
Raises:
-
TypeError–countis not a whole number. -
ValueError–countis negative.
Source code in xnano/placement.py
down
¶
Move the placement down by count rows; see move.
Parameters:
-
count(int, default:1) –How many rows to move.
Raises:
-
TypeError–countis not a whole number. -
ValueError–countis negative.
Source code in xnano/placement.py
left
¶
Move the placement left by count columns; see move.
Parameters:
-
count(int, default:1) –How many columns to move.
Raises:
-
TypeError–countis not a whole number. -
ValueError–countis negative.
Source code in xnano/placement.py
right
¶
Move the placement right by count columns; see move.
Parameters:
-
count(int, default:1) –How many columns to move.
Raises:
-
TypeError–countis not a whole number. -
ValueError–countis negative.
Source code in xnano/placement.py
render
¶
Draw the placement, with its border, padding and nested placements, to a string.
Parameters:
-
format(Literal['text', 'ansi'], default:'text') –'text'for the characters only,'ansi'with colors and styles.
Examples:
import xnano
with xnano.new(width=10, height=3) as canvas:
card = canvas.write('hi', border='rounded')
assert card.render().splitlines() == ['╭──╮', '│hi│', '╰──╯']
Source code in xnano/placement.py
refresh
¶
Draw a placement made from a component again, at the next frame.
A component is evaluated once, and again only when it read something that changes. When
something it does not track changes, such as a field of a class-based component or a
value in context.deps, call this to evaluate it again. A placement that was not made
from a component has nothing to evaluate, so this does nothing.
Examples:
import xnano
@xnano.renderable
def counter(context: xnano.Context) -> str:
return str(context.deps['count'])
dependencies = {'count': 0}
with xnano.new(width=4, height=1, deps=dependencies) as canvas:
placement = canvas.write(counter)
dependencies['count'] = 7
placement.refresh()
canvas.step()
assert canvas.render().strip() == '7'
Source code in xnano/placement.py
write
¶
write(content: Content | Canvas[WrittenDepsT, WrittenStateT] | None = None, /, *, x: Axis | None = None, y: Axis | None = None, width: Axis | None = None, height: Axis | None = None, layer: int = 0, lock: bool = False, edges: EdgeBehavior | None = None, effects: Sequence[RenderableEffectSpecification] = (), style: Style | None = None, foreground: ColorValue | None = None, background: ColorValue | None = None, bold: bool = False, dim: bool = False, italic: bool = False, underline: bool = False, blink: bool = False, reverse: bool = False, hidden: bool = False, crossed_out: bool = False, title: str | None = None, border: BorderKind | bool | None = None, border_style: Style | None = None, padding: Spacing | None = None, margin: Spacing | None = None) -> Placement[DepsT, StateT]
Add a child placement inside this placement.
A child placement's x, y, width and height are measured relative to
this placement's buffer, so track.write('█', x=(0, track.width - 1), y=0) moves
inside track. To change this placement with an operation, a style or an effect, use
update.
Parameters:
-
content(Content | Canvas[WrittenDepsT, WrittenStateT] | None, default:None) –Child content to place inside this buffer.
-
x(Axis | None, default:None) –Column of the child's left edge, relative to this placement.
-
y(Axis | None, default:None) –Row of the child's top edge, relative to this placement.
-
width(Axis | None, default:None) –Width of the child in cells.
-
height(Axis | None, default:None) –Height of the child in cells.
-
layer(int, default:0) –Layer ordering among siblings.
-
lock(bool, default:False) –Lock dynamic axes to their initial values.
-
edges(EdgeBehavior | None, default:None) –What the content does at the edges of its area:
'clip','stop'or'wrap'; seePlacement.edges. Left out, it follows what it is written on. -
effects(Sequence[RenderableEffectSpecification], default:()) –Effects to start on the child, as dictionaries with a
kindkey. -
style(Style | None, default:None) –Ready-made
Stylefor text. -
foreground(ColorValue | None, default:None) –Text foreground color.
-
background(ColorValue | None, default:None) –Text background color.
-
bold(bool, default:False) –Whether text is bold.
-
dim(bool, default:False) –Whether text is dimmed.
-
italic(bool, default:False) –Whether text is italic.
-
underline(bool, default:False) –Whether text is underlined.
-
blink(bool, default:False) –Whether text blinks.
-
reverse(bool, default:False) –Whether foreground and background are swapped.
-
hidden(bool, default:False) –Whether text is hidden.
-
crossed_out(bool, default:False) –Whether text is struck through.
-
title(str | None, default:None) –Title for a box around text.
-
border(BorderKind | bool | None, default:None) –The kind of border for a box around the content, a
BorderKindsuch as'plain','rounded','double'or'thick';Truefor'plain'andFalsefor none. -
border_style(Style | None, default:None) –Style for the box's border.
-
padding(Spacing | None, default:None) –Space between the border and the text; see
Canvas.write. -
margin(Spacing | None, default:None) –Space outside the box, in the same forms.
Source code in xnano/placement.py
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 | |
update
¶
Change this placement's content with operations, styles or effects.
Parameters:
-
operations(Operation | Style, default:()) –What to apply, in order: an operation, a contextual operation, a style, or an effect such as
Effect.dissolve(duration_milliseconds=500).
Examples:
import xnano
from xnano.effects import Effect
with xnano.new(width=20, height=3) as canvas:
title = canvas.write('Welcome')
title.update(Effect.dissolve(duration_milliseconds=500))
Source code in xnano/placement.py
__or__
¶
__ior__
¶
Apply operation to this placement in place and return self.
remove
¶
Take the buffer off the canvas. Removing twice is harmless.
Source code in xnano/placement.py
__setattr__
¶
Set an attribute, or raise AttributeError for an unknown public name.
Source code in xnano/_attributes.py
bold
¶
bold(value: bool = True) -> Self
Make the text bold, or undo it with False; the same as setting is_bold.
Parameters:
-
value(bool, default:True) –Whether the text is bold.
Returns:
-
Self–This canvas or placement, so calls can chain.
Raises:
-
TypeError–valueis notTrueorFalse.
Examples:
import xnano
with xnano.new(width=12, height=1) as canvas:
title = canvas.write('Ready').bold().underline()
assert title.is_bold and title.is_underlined
title.bold(False)
assert not title.is_bold
Source code in xnano/appearance.py
dim
¶
dim(value: bool = True) -> Self
Dim the text, or undo it with False; the same as setting is_dim.
Parameters:
-
value(bool, default:True) –Whether the text is dimmed.
Returns:
-
Self–This canvas or placement, so calls can chain.
Raises:
-
TypeError–valueis notTrueorFalse.
Source code in xnano/appearance.py
italic
¶
italic(value: bool = True) -> Self
Make the text italic, or undo it with False; the same as setting is_italic.
Parameters:
-
value(bool, default:True) –Whether the text is italic.
Returns:
-
Self–This canvas or placement, so calls can chain.
Raises:
-
TypeError–valueis notTrueorFalse.
Source code in xnano/appearance.py
underline
¶
underline(value: bool = True) -> Self
Underline the text, or undo it with False; the same as setting is_underlined.
Parameters:
-
value(bool, default:True) –Whether the text is underlined.
Returns:
-
Self–This canvas or placement, so calls can chain.
Raises:
-
TypeError–valueis notTrueorFalse.
Source code in xnano/appearance.py
blink
¶
blink(value: bool = True) -> Self
Make the text blink, or undo it with False; the same as setting is_blinking.
Parameters:
-
value(bool, default:True) –Whether the text blinks.
Returns:
-
Self–This canvas or placement, so calls can chain.
Raises:
-
TypeError–valueis notTrueorFalse.
Source code in xnano/appearance.py
reverse
¶
reverse(value: bool = True) -> Self
Swap the foreground and background, or undo it with False; the same as setting is_reversed.
Parameters:
-
value(bool, default:True) –Whether foreground and background are swapped.
Returns:
-
Self–This canvas or placement, so calls can chain.
Raises:
-
TypeError–valueis notTrueorFalse.
Source code in xnano/appearance.py
hidden
¶
hidden(value: bool = True) -> Self
Hide the text, or undo it with False; the same as setting is_hidden.
Parameters:
-
value(bool, default:True) –Whether the text is hidden.
Returns:
-
Self–This canvas or placement, so calls can chain.
Raises:
-
TypeError–valueis notTrueorFalse.
Source code in xnano/appearance.py
crossed_out
¶
crossed_out(value: bool = True) -> Self
Strike the text through, or undo it with False; the same as setting is_crossed_out.
Parameters:
-
value(bool, default:True) –Whether the text is struck through.
Returns:
-
Self–This canvas or placement, so calls can chain.
Raises:
-
TypeError–valueis notTrueorFalse.
Source code in xnano/appearance.py
hook
¶
hook(function: Hook[DepsT, StateT] | None = None, /, *, on: HookKind | None = None, when: When[DepsT, StateT] | None = None, every: float | None = None, after: float | None = None, keys: KeyName | Sequence[KeyName] | None = None, requires_deps: bool = False) -> HookHandle[DepsT, StateT] | Callable[[Hook[DepsT, StateT]], HookHandle[DepsT, StateT]]
Call a function when something happens on this canvas or placement.
on says what to listen to. A hook without on hears every input event. A mouse,
scroll or drag hook on a placement hears only the pointer inside the placement, and a
press inside holds the pointer for the hook until the button is released. A pointer hook
that matches an event stops it from reaching the parent; a hook that does not match lets
it through. Keys are not consumed: while nothing has focus, every key hook hears a key.
hook(function, ...) attaches one function, and @target.hook(...) decorates the
function that follows. A hook function may be a generator that receives a new context
at each bare yield: write context = yield. A drag is a loop that runs while
context.mouse.is_down.
every and after are seconds for on='tick' and beats for on='beat':
every=2 means 2 seconds for a tick hook and 2 beats for a beat hook. On a canvas
from new() a hook that is due several times in one step runs once for each
interval, up to 100,000 times in one step; the intervals that remain run in the steps
that follow. The function's return value is ignored, unless it is an operation, a
style or an effect, which is applied to this target.
Parameters:
-
function(Hook[DepsT, StateT] | None, default:None) –The function to call with a
Context, or a function with no parameters, which is called without it. -
on(HookKind | None, default:None) –What to listen to:
'frame','tick','beat','key','mouse','scroll','drag','paste','focus','resize','state'or'custom'. SeeHookKind. -
when(When[DepsT, StateT] | None, default:None) –A condition that must hold: an expression, a function of the context, or a string. See
When. A string tells xnano which input the hook needs, so the mouse, scroll and key-release gates it reads are turned on when the canvas opens. An expression or a function does not, so a condition that readsMouse,Scrollor key releases needs the gate set onnew()oropen()yourself:mouse=True,scroll=Trueorkeyboard='release_events'. A comparison with an input the event does not carry, such askeyboard.keyon a paste, does not hold;!=is one of them, sokeyboard.key != 'q'hears only key events.notandnot innegate the whole comparison, sonot keyboard.key == 'q'andkeyboard.key not in ['q']also hold for events that have no key. -
every(float | None, default:None) –Repeat every this many seconds (
'tick') or beats ('beat'). -
after(float | None, default:None) –Run once after this many seconds (
'tick') or beats ('beat'). -
keys(KeyName | Sequence[KeyName] | None, default:None) –The key or keys an
on='key'hook reacts to, such as'q'or'ctrl+s'. A key hook with keys hears presses and repeats; omit them and testkeyboard.kindto hear releases. -
requires_deps(bool, default:False) –Whether the hook needs the dependencies given to
new(deps=...).
Returns:
-
HookHandle[DepsT, StateT] | Callable[[Hook[DepsT, StateT]], HookHandle[DepsT, StateT]]–The hook, whose
removestops it; or, without a function, the decorator.
Raises:
-
ValueError–The combination of arguments does not make sense, a key name is unknown, or a
whenstring is not a condition. The message says what to write instead. -
TypeError–onis not text,whenis a plainbool, or the function is not callable with a context, or is anasyncfunction. -
TerminalError–requires_depsis true and the canvas was created withoutdeps, or the canvas is on a screen with an input gate this hook needs turned off.
Examples:
import xnano
from xnano_core import Event
with xnano.new(width=8, height=1) as canvas:
heard = []
@canvas.hook(on='key', keys=['q', 'escape'])
def leave(context: xnano.Context) -> None:
heard.append(context.keyboard.key)
@canvas.hook(on='tick', every=0.5)
def blink(context: xnano.Context) -> None:
heard.append('tick')
canvas.push(Event.key_press('q'))
canvas.step(delta_seconds=1.0)
assert heard == ['q', 'tick', 'tick']
Source code in xnano/_hooks.py
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 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 | |