Quick search

Text layout

An internal module for laying out text according to options and constraints. This is not part of the API and may change at any time.

class kivy.core.text.text_layout.LayoutLine

Bases: builtins.object

Formally describes a line of text. A line of text is composed of many LayoutWord instances, each with it’s own text, size and options.

A LayoutLine instance does not always imply that the words contained in the line ended with a newline. That is only the case if is_last_line is True. For example a single real line of text can be split across multiple LayoutLine instances if the whole line doesn’t fit in the constrained width.

x: int

the location in a texture from where the left side of this line is began drawn.

y: int

the location in a texture from where the bottom of this line is drawn.

w: int

the width of the line. This is the sum of the individual widths of its LayoutWord instances. Does not include any padding.

h: int

the height of the line. This is the maximum of the individual heights of its LayoutWord instances multiplied by the line_height of these instance. So this is larger then the word height.

is_last_line: bool

whether this line was the last line in a paragraph. When True, it implies that the line was followed by a newline. Newlines should not be included in the text of words, but is implicit by setting this to True.

line_wrap: bool

whether this line is continued from a previous line which didn’t fit into a constrained width and was therefore split across multiple LayoutLine instances. line_wrap can be True or False independently of is_last_line.

words: python list

a list that contains only LayoutWord instances describing the text of the line.


h: ‘int’


is_last_line: ‘int’


line_wrap: ‘int’


w: ‘int’


words: list


x: ‘int’


y: ‘int’

class kivy.core.text.text_layout.LayoutWord

Bases: builtins.object

Formally describes a word contained in a line. The name word simply means a chunk of text and can be used to describe any text.

A word has some width, height and is rendered according to options saved in options. See LayoutLine for its usage.

options: dict

the label options dictionary for this word.

lw: int

the width of the text in pixels.

lh: int

the height of the text in pixels.

text: string

the text of the word.


lh: ‘int’


lw: ‘int’


options: dict


text: object

kivy.core.text.text_layout.layout_text(text, list lines, tuple size, tuple text_size, dict options, get_extents, int append_down, int complete)

Lays out text into a series of LayoutWord and LayoutLine instances according to the options specified.

The function is designed to be called many times, each time new text is appended to the last line (or first line if appending upwards), unless a newline is present in the text. Each text appended is described by its own options which can change between successive calls. If the text is constrained, we stop as soon as the constraint is reached.

text: string or bytes

the text to be broken down into lines. If lines is not empty, the text is added to the last line (or first line if append_down is False) until a newline is reached which creates a new line in lines. See LayoutLine.

lines: list

a list of LayoutLine instances, each describing a line of the text. Calls to layout_text() append or create new LayoutLine instances in lines.

size: 2-tuple of ints

the size of the laid out text so far. Upon first call it should probably be (0, 0), afterwards it should be the (w, h) returned by this function in a previous call. When size reaches the constraining size, text_size, we stop adding lines and return True for the clipped parameter. size includes the x and y padding.

text_size: 2-tuple of ints or None.

the size constraint on the laid out text. If either element is None, the text is not constrained in that dimension. For example, (None, 200) will constrain the height, including padding to 200, while the width is unconstrained. The first line, and the first character of a line is always returned, even if it exceeds the constraint. The value be changed between different calls.

options: dict

the label options of this text. The options are saved with each word allowing different words to have different options from successive calls.

Note, options must include a space_width key with a value indicating the width of a space for that set of options.

get_extents: callable

a function called with a string, which returns a tuple containing the width, height of the string.

append_down: bool

Whether successive calls to the function appends lines before or after the existing lines. If True, they are appended to the last line and below it. If False, it’s appended at the first line and above. For example, if False, everything after the last newline in text is appended to the first line in lines. Everything before the last newline is inserted at the start of lines in same order as text; that is we do not invert the line order.

This allows laying out from top to bottom until the constrained is reached, or from bottom to top until the constrained is reached.

complete: bool

whether this text complete lines. It use is that normally is strip in options is True, all leading and trailing spaces are removed from each line except from the last line (or first line if append_down is False) which only removes leading spaces. That’s because further text can still be appended to the last line so we cannot strip them. If complete is True, it indicates no further text is coming and all lines will be stripped.

The function can also be called with text set to the empty string and complete set to True in order for the last (first) line to be stripped.


3-tuple, (w, h, clipped). w and h is the width and height of the text in lines so far and includes padding. This can be larger than text_size, e.g. if not even a single fitted, the first line would still be returned. clipped is True if not all the text has been added to lines because w, h reached the constrained size.

Following is a simple example with no padding and no stripping:

>>> from kivy.core.text import Label
>>> from kivy.core.text.text_layout import layout_text

>>> l = Label()
>>> lines = []
>>> # layout text with width constraint by 50, but no height constraint
>>> w, h, clipped = layout_text('heres some text\nah, another line',
... lines, (0, 0), (50, None), l.options, l.get_cached_extents(), True,
... False)
>>> w, h, clipped
(46, 90, False)
# now add text from bottom up, and constrain width only be 100
>>> w, h, clipped = layout_text('\nyay, more text\n', lines, (w, h),
... (100, None), l.options, l.get_cached_extents(), False, True)
>>> w, h, clipped
(77, 120, 0)
>>> for line in lines:
...     print('line w: {}, line h: {}'.format(line.w, line.h))
...     for word in line.words:
...         print('w: {}, h: {}, text: {}'.format(word.lw, word.lh,
...         [word.text]))
line w: 0, line h: 15
line w: 77, line h: 15
w: 77, h: 15, text: ['yay, more text']
line w: 31, line h: 15
w: 31, h: 15, text: ['heres']
line w: 34, line h: 15
w: 34, h: 15, text: [' some']
line w: 24, line h: 15
w: 24, h: 15, text: [' text']
line w: 17, line h: 15
w: 17, h: 15, text: ['ah,']
line w: 46, line h: 15
w: 46, h: 15, text: [' another']
line w: 23, line h: 15
w: 23, h: 15, text: [' line']