#!/usr/bin/env python
# -*- coding: utf-8 -*-
# It script it publish under GNU GENERAL PUBLIC LICENSE
# http://www.gnu.org/licenses/gpl-3.0.en.html
# Author: the Galaxie Curses Team, all rights reserved
import GLXCurses
import textwrap
import logging
[docs]class Label(GLXCurses.Misc, GLXCurses.Movable):
def __init__(self):
# Load heritage
GLXCurses.Misc.__init__(self)
GLXCurses.Movable.__init__(self)
# It's a GLXCurse Type
self.glxc_type = "GLXCurses.Label"
self.name = "{0}{1}".format(self.__class__.__name__, self.id)
# Label Properties
self.__angle = None
self.angle = None
self.__attributes = None
self.attributes = None
self.__cursor_position = None
self.cursor_position = None
self.justify = GLXCurses.GLXC.JUSTIFY_LEFT
self.__label = None
self.label = None
self.__lines = None
self.lines = None
self.__max_width_chars = None
self.max_width_chars = None
self.__mnemonic_keyval = None
self.mnemonic_keyval = None
self.__mnemonic_widget = None
self.mnemonic_widget = None
self.__pattern = None
self.pattern = None
self.__selectable = False
self.selectable = False
self.__selection_bound = None
self.selection_bound = None
self.__single_line_mode = None
self.single_line_mode = None
self.__track_visited_links = None
self.track_visited_links = None
self.__use_markdown = None
self.use_markdown = None
self.__use_underline = None
self.use_underline = None
self.__width_chars = None
self.width_chars = None
self.__wrap = None
self.wrap = None
self.__wrap_mode = None
self.wrap_mode = GLXCurses.GLXC.WRAP_WORD
self.text_x = 0
self.text_y = 0
##############
# Properties #
##############
@property
def angle(self):
"""
The angle that the baseline of the label makes with the horizontal, in degrees, measured counterclockwise.
An angle of 90 reads from from bottom to top, an angle of 270, from top to bottom.
Ignored if the label is selectable.
Allowed values: [0,360]
:return: angle that the baseline of the label
:rtype: int
"""
return self.__angle
@angle.setter
def angle(self, angle=None):
"""
Set the ``angle`` property value
:param angle: The angle that the baseline of the label makes with the horizontal
:type angle: int [0,360]
:raise TypeError: When ``angle`` property value is not int type or None
:raise ValueError: When ``angle`` property value is in allowed range [0,360]
"""
if angle is None:
angle = 0
if type(angle) != int:
raise TypeError("'angle' value must be a int type or None")
if angle < 0 or angle > 360:
raise ValueError("'angle' allowed value is [0,360]")
if self.angle != angle:
self.__angle = angle
@property
def attributes(self):
"""
A list of style attributes to apply to the text of the label.
:return: A list of style attributes
:rtype: list
"""
return self.__attributes
@attributes.setter
def attributes(self, attributes=None):
"""
Set the ``attributes`` property value
:param attributes: A list of style attributes
:type attributes: list
:raise TypeError: When ``attribute`` property value is not a list type or None
"""
if attributes is None:
attributes = []
if type(attributes) != list:
raise TypeError("'attributes' property value must be a list type or None")
if self.attributes != attributes:
self.__attributes = attributes
@property
def cursor_position(self):
"""
The current position of the insertion cursor in chars.
:return: The ``cursor_position`` property value
:rtype: int
"""
return self.__cursor_position
@cursor_position.setter
def cursor_position(self, cursor_position=None):
"""
Set the ``cursor_position`` property value
:param cursor_position: The current position of the insertion cursor in chars
:type cursor_position: int
:raise TypeError: When ``cursor_position`` property value is not a int type or None
:raise ValueError: When ``cursor_position`` property value is not > or = to zero
"""
if cursor_position is None:
cursor_position = 0
if type(cursor_position) != int:
raise TypeError("'cursor_position' property value must be int type or None")
if cursor_position < 0:
raise ValueError("'cursor_position' property value must be > or = to zero")
if self.cursor_position != cursor_position:
self.__cursor_position = cursor_position
@property
def label(self):
"""
The contents of the label.
If the string contains TXT MarkDown, you will have to set the ``use_markdown`` property to True in order for
the label to display the MarkDown attributes.
See also set_markdown() for a convenience function that sets both this property and the ``use_markdown``
property at the same time.
If the string contains underlines acting as mnemonics, you will have to set the ``use_underline`` property
to True in order for the label to display them.
:return: The content of the label
:rtype: str
"""
return self.__label
@label.setter
def label(self, label=None):
"""
Set the ``label`` property value
:param label: Contents of the label
:type label: str or None
:raise TypeError: When ``label`` property value is not str type or None
"""
if label is None:
label = ""
if type(label) != str:
raise TypeError('"label" must be a str type or None')
if self.label != label:
self.__label = label
@property
def lines(self):
"""
The number of lines to which an ellipsized, wrapping label should be limited. This property has no effect if
the label is not wrapping or ellipsized.
Set this property to -1 if you don't want to limit the number of lines.
:return: The number of lines to which an ellipsized
:rtype: int
"""
return self.__lines
@lines.setter
def lines(self, lines=None):
"""
Set the ``lines`` property value
:param lines: The number of lines to which an ellipsized
:type lines: int
:raise TypeError: When ``lines`` property is not a int type or None
:raise ValueError: When ``lines`` property value is not >= to -1
"""
if lines is None:
lines = -1
if type(lines) != int:
raise TypeError("'lines' property value must be int type or None")
if not lines >= -1:
raise ValueError("'lines' property value must be >= to -1")
if self.lines != lines:
self.__lines = lines
@property
def max_width_chars(self):
"""
The desired maximum width of the label, in characters.
If this property is set to -1, the width will be calculated automatically.
See the section on text layout for details of how ``width_chars`` and ``max_width_chars`` determine the width
of ellipsized and wrapped labels.
:return: Maximum width of the label, in characters
:rtype: int
"""
return self.__max_width_chars
@max_width_chars.setter
def max_width_chars(self, max_width_chars=None):
"""
Set the ``max_width_chars`` property value
:param max_width_chars: The desired maximum width of the label, in characters.
:type max_width_chars: int
:raise TypeError: When ``max_width_chars`` property is not a int type or None
:raise ValueError: When ``max_width_chars`` property value is not >= to -1
"""
if max_width_chars is None:
max_width_chars = -1
if type(max_width_chars) != int:
raise TypeError("'max_width_chars' property value must be int type or None")
if not max_width_chars >= -1:
raise ValueError("'max_width_chars' property value must be >= to -1")
if self.max_width_chars != max_width_chars:
self.__max_width_chars = max_width_chars
@property
def mnemonic_keyval(self):
"""
The mnemonic accelerator key for this label.
Default value: 16777215
"""
return self.__mnemonic_keyval
@mnemonic_keyval.setter
def mnemonic_keyval(self, mnemonic_keyval=None):
"""
Set the ``mnemonic_keyval`` property value
:param mnemonic_keyval: The mnemonic accelerator key.
:type mnemonic_keyval: int
:raise TypeError: When ``mnemonic_keyval`` is not a int type or None
"""
if mnemonic_keyval is None:
mnemonic_keyval = 16777215
if type(mnemonic_keyval) != int:
raise TypeError(
"'mnemonic_keyval' property value must be a int type or None"
)
if self.mnemonic_keyval != mnemonic_keyval:
self.__mnemonic_keyval = mnemonic_keyval
@property
def mnemonic_widget(self):
"""
The GLXCurses.Widget to be activated when the label's mnemonic key is pressed.
:return: The GLXCurses.Widget to be activated or None if not set
:rtype GLXCurses.Widget or None
"""
return self.__mnemonic_widget
@mnemonic_widget.setter
def mnemonic_widget(self, mnemonic_widget=None):
"""
Set the ``mnemonic_widget`` property value
:param mnemonic_widget: The GLXCurses.Widget to be activated or None
:type mnemonic_widget: GLXCurses.Widget or None
:raise TypeError: When ``mnemonic_widget`` property value is not a GLXCurses.Widget or None
"""
if mnemonic_widget is not None and not isinstance(
mnemonic_widget, GLXCurses.Widget
):
raise TypeError(
"'mnemonic_widget' property value must be a GLXCurses.Widget or None"
)
if self.mnemonic_widget != mnemonic_widget:
self.__mnemonic_widget = mnemonic_widget
@property
def pattern(self):
"""
A string with _ characters in positions correspond to characters in the text to underline.
:return: characters in the text use for underline
:rtype: str
"""
return self.__pattern
@pattern.setter
def pattern(self, pattern=None):
"""
Set the ``pattern`` property value
:param pattern: characters in the text use for underline
:type pattern: str or None
"""
if pattern is not None and type(pattern) != str:
raise TypeError("'pattern' property value must be a str type or None")
if self.pattern != pattern:
self.__pattern = pattern
@property
def selectable(self):
"""
Whether the GLXCurses.Label text can be selected with the mouse.
:return: True if GLXCurses.Label text can be selected
:rtype: bool
"""
return self.__selectable
@selectable.setter
def selectable(self, selectable=None):
"""
Set the ``selectable`` property value
:param selectable: True if GLXCurses.Label text can be selected
:type selectable: bool or None
:raise TypeError: When ``selectable`` property value is not bool type or None
"""
if selectable is None:
selectable = False
if type(selectable) != bool:
raise TypeError("'selectable' property value must be bool type or None")
if self.selectable != selectable:
self.__selectable = selectable
@property
def selection_bound(self):
"""
The position of the opposite end of the selection from the cursor in chars.
:return: The position in chars
:rtype: int
"""
return self.__selection_bound
@selection_bound.setter
def selection_bound(self, selection_bound=None):
"""
Set the ``selection_bound`` property value
Allowed values: >= 0
:param selection_bound: The position in chars
:type selection_bound: int or None
:raise TypeError: When ``selection_bound`` property value is not int type or None
:raise ValueError: When ``selection_bound`` property value is not >= to 0
"""
if selection_bound is None:
selection_bound = 0
if type(selection_bound) != int:
raise TypeError("'selection_bound' must be a int type or None")
if not selection_bound >= 0:
raise ValueError("'selection_bound' must be >= to 0")
if self.selection_bound != selection_bound:
self.__selection_bound = selection_bound
@property
def single_line_mode(self):
"""
Whether the label is in single line mode. In single line mode, the height of the label does not depend on the
actual text, it is always set to ascent + descent of the font.
This can be an advantage in situations where resizing the label because of text changes would be distracting,
e.g. in a GLXCurses.StatusBar or GLXCurses.MessageBar.
Default value: False
:return: True if label is in single line mode
:rtype: bool
"""
return self.__single_line_mode
@single_line_mode.setter
def single_line_mode(self, single_line_mode=None):
"""
Set the ``single_line_mode`` property value
:param single_line_mode:True if label is in single line mode
:type single_line_mode: bool or None
:raise TypeError: When ``single_line_mode`` property value is not a bool type or None
"""
if single_line_mode is None:
single_line_mode = False
if type(single_line_mode) != bool:
raise TypeError(
"'single_line_mode' property value must be a bool type or None"
)
if self.single_line_mode != single_line_mode:
self.__single_line_mode = single_line_mode
@property
def track_visited_links(self):
"""
Set this property to True to make the label track which links have been visited.
It will then apply the GLXC.STATE_FLAG_VISITED when rendering this link, in addition to GLXC.STATE_FLAG_LINK.
Default value: True
:return: True if label track which links have been visited
:rtype: bool
"""
return self.__track_visited_links
@track_visited_links.setter
def track_visited_links(self, track_visited_links=None):
"""
Set the ``track_visited_links`` property value
:param track_visited_links: True if label track which links have been visited
:type track_visited_links: bool or None
:raise TypeError: When ``track_visited_links`` property value is not a bool type or None
"""
if track_visited_links is None:
track_visited_links = True
if type(track_visited_links) != bool:
raise TypeError(
"'track_visited_links' property value must be a bool type or None"
)
if self.track_visited_links != track_visited_links:
self.__track_visited_links = track_visited_links
@property
def use_markdown(self):
"""
The text of the label includes TXT MarkDown.
Default value: False
:return: True if MarkDown is used
:rtype: bool
"""
return self.__use_markdown
@use_markdown.setter
def use_markdown(self, use_markdown=None):
"""
Set the ``use_markdown`` property value
:param use_markdown: True if MarkDown is used
:type use_markdown: bool or None
:raise TypeError: When ``use_markdown`` property value is not a bool type or None
"""
if use_markdown is None:
use_markdown = False
if type(use_markdown) != bool:
raise TypeError("'use_markdown' property value must be a bool type or None")
if self.use_markdown != use_markdown:
self.__use_markdown = use_markdown
@property
def use_underline(self):
"""
If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key.
Default value: False
:return: True if underline is display on text when use a mnemonic accelerator key
:rtype: bool
"""
return self.__use_underline
@use_underline.setter
def use_underline(self, use_underline=None):
"""
Set the ``use_underline`` property value
:param use_underline: if True a underline will be display on text when use a mnemonic accelerator key
:type use_underline: bool or None
:raise TypeError: When ``use_underline`` property value is not a bool type or None
"""
if use_underline is None:
use_underline = False
if type(use_underline) != bool:
raise TypeError(
"'use_underline' property value must be a bool type or None"
)
if self.use_underline != use_underline:
self.__use_underline = use_underline
@property
def width_chars(self):
"""
The desired width of the label, in characters. If this property is set to -1, the width will be calculated
automatically.
See the section on text layout for details of how ``width_chars`` and ``max_width_chars`` determine the width
of ellipsized and wrapped labels.
:return: The desired width of the label, in characters.
:rtype: int
"""
return self.__width_chars
@width_chars.setter
def width_chars(self, width_chars=None):
"""
Set the ``width_chars`` property value
:param width_chars: The desired width of the label, in characters or None
:type width_chars: int or None
:raise TypeError: When ``width_chars`` property value is not a int type or None
:raise ValueError: When ``width_chars`` property value is not >= to -1
"""
if width_chars is None:
width_chars = -1
if type(width_chars) != int:
raise TypeError("'width_chars' property value must be a int type or None")
if not width_chars >= -1:
raise ValueError("'width_chars' property value must be >= to -1")
if self.width_chars != width_chars:
self.__width_chars = width_chars
@property
def wrap(self):
"""
If set, wrap lines if the text becomes too wide.
:return: True if wrap is in use
:rtype: bool
"""
return self.__wrap
@wrap.setter
def wrap(self, wrap=None):
"""
Set the ``wrap`` property value
:param wrap: True if wrap is in use
:type wrap: bool or None
:raise TypeError: When ``wrap`` property value is not bool type or None
"""
if wrap is None:
wrap = False
if type(wrap) != bool:
raise TypeError("'wrap' property value must be bool type or None")
if self.wrap != wrap:
self.__wrap = wrap
@property
def wrap_mode(self):
"""
If line wrapping is on (see the ``wrap`` property) this controls how the line wrapping is done.
The default is GLXC.WRAP_WORD, which means wrap on word boundaries.
:return: How the line wrapping is done
:rtype: GLXCurses.GLXC.WrapMode
"""
return self.__wrap_mode
@wrap_mode.setter
def wrap_mode(self, wrap_mode=None):
"""
Set the ``wrap_mode`` property value
:param wrap_mode: How the line wrapping is done or None
:type wrap_mode: GLXCurses.GLXC.WrapMode
"""
if wrap_mode is None:
wrap_mode = GLXCurses.GLXC.WRAP_WORD
if type(wrap_mode) != str:
raise TypeError("'wrap_mode' property value must be a str type or None")
if str(wrap_mode).upper() not in GLXCurses.GLXC.WrapMode:
raise ValueError("'wrap_mode' must be a valid GLXC.WrapMode")
if self.wrap_mode != wrap_mode:
self.__wrap_mode = wrap_mode
###########
# Methods #
###########
[docs] def new(self, string=None):
"""
Creates a new label with the given text inside it.
You can pass None to get an empty GLXCurses.Label.
:param string: The text of the GLXCurses.Label.
:type string: str or None
:return: The new GLXCurses.Label it self
:rtype: GLXCurses.Label
"""
self.__init__()
if string:
self.label = string
self.use_markdown = False
self.mnemonic_keyval = None
self.mnemonic_widget = None
self.justify = GLXCurses.GLXC.JUSTIFY_LEFT
self.attributes = GLXCurses.TextAttributes().parse(
label=self.label,
markdown_is_used=self.use_markdown,
mnemonic_is_used=False,
mnemonic_char=self.pattern,
mnemonic_use_underline=self.use_underline,
)
return self
[docs] def set_text(self, string=None):
"""
Sets the text within the GtkLabel widget. It overwrites any text that was there before.
This function will clear any previously set mnemonic accelerators,
and set the ``use_underline`` property to False as a side effect.
This function will set the ``use_markdown`` property to False as a side effect.
See also: GLXCurses.Label().set_markdown()
:param string: The text you want to set
:type string: str or None
"""
self.label = string
self.mnemonic_keyval = None
self.mnemonic_widget = None
self.use_underline = False
self.use_markdown = False
self.update_preferred_sizes()
[docs] def set_attributes(self, attributes=None):
"""
Sets a GLXC.StateFlags; the attributes in the list are applied to the label text.
The attributes set with this function will be applied and merged with any other attributes previously effected
by way of the ``use_underline`` or ``use_markup`` properties.
While it is not recommended to mix markdown strings with manually set attributes, if you must; know that the
attributes will be applied to the label after the markdown string is parsed.
:param attributes: a GLXC.StateFlags
:type attributes: list or None
"""
self.attributes = attributes
[docs] def set_markdown(self, string=None):
"""
Parses ``string`` which is marked down with the text markdown language, setting the label’s text and
attribute list based on the parse results.
This function will set the ``use_markup`` property to ``True`` as a side effect.
If you set the label contents using the ``label`` property you should also ensure that you set the
``use_markup`` property accordingly.
See also: GLXCurses.Label().set_text()
:param string: A markdown string (see text markdown format)
:type string: str
"""
self.label = string
self.attributes = GLXCurses.TextAttributes().parse(
label=self.label,
markdown_is_used=True,
mnemonic_char=self.pattern,
mnemonic_use_underline=self.use_underline,
mnemonic_is_used=False,
)
self.use_markdown = True
if self.parent:
self.mnemonic_widget = self.parent
else:
self.mnemonic_widget = self
self.update_preferred_sizes()
[docs] def set_markdown_with_mnemonic(self, string):
"""
Parses ``string`` which is marked down with the text markdown language, setting the label’s text and
attribute list based on the parse results.
If characters in ``string`` are preceded by an underscore, they are
underlined indicating that they represent a keyboard accelerator called a mnemonic.
The mnemonic key can be used to activate another GLXCurses.Widget, chosen automatically, or explicitly using
GLXCurses.Label().set_mnemonic_widget().
:param string: A markdown string (see text markdown format)
:type string: str
"""
self.label = string
self.use_markdown = True
self.attributes = GLXCurses.TextAttributes().parse(
label=self.label,
markdown_is_used=self.use_markdown,
mnemonic_is_used=True,
mnemonic_char=self.pattern,
mnemonic_use_underline=self.use_underline,
)
for item in self.attributes:
if "MNEMONIC" in item and item["MNEMONIC"]:
if "CHAR" in item and item["CHAR"]:
self.mnemonic_keyval = ord(item["CHAR"])
if self.parent:
self.mnemonic_widget = self.parent
else:
self.mnemonic_widget = self
self.update_preferred_sizes()
[docs] def set_pattern(self, pattern=None):
"""
The pattern of underlines you want under the existing text within the GLXCurses.Label widget.
For example if the current text of the label says “FooBarBaz” passing a pattern
of “___ ___” will underline “Foo” and “Baz” but not “Bar”.
:param pattern: The pattern as described above.
:type pattern: str or None
"""
self.pattern = pattern
[docs] def set_justify(self, jtype=None):
"""
Sets the alignment of the lines in the text of the label relative to each other.
GLXCurses.GLXC.JUSTIFY_LEFT is the default value when the widget is first created with GLXCurses.Label().new()
If you instead want to set the alignment of the label as a whole, use
GLXCurses.Widget().set_halign() instead.
GLXCurses.Label().set_justify() has no effect on labels containing only a single line.
:param jtype: a GLXCurses.GLXC.Justification
:type jtype: str or None
"""
if not self.single_line_mode or len(str(self.label).split("\n")) > 1:
self.justify = jtype
if self.justify == GLXCurses.GLXC.JUSTIFY_CENTER:
self.xalign = 0.5
elif self.justify == GLXCurses.GLXC.JUSTIFY_RIGHT:
self.xalign = 1.0
elif self.justify == GLXCurses.GLXC.JUSTIFY_LEFT:
self.xalign = 0.0
[docs] def set_xalign(self, xalign=None):
"""
Sets the ``xalign`` property for label .
:param xalign: the new xalign value, between 0 and 1
:type xalign: float or None
"""
self.xalign = xalign
[docs] def set_yalign(self, yalign=None):
"""
Sets the ``yalign`` property for label .
:param yalign: the new yalign value, between 0 and 1
:type yalign: float or None
"""
self.yalign = yalign
[docs] def set_width_chars(self, n_chars=None):
"""
Sets the desired width in characters of label to ``n_chars`` .
:param n_chars: the new desired width, in characters.
:type n_chars: int or None
"""
self.width_chars = n_chars
[docs] def set_max_width_chars(self, n_chars):
"""
Sets the desired maximum width in characters of label to ``n_chars`` .
:param n_chars: the new desired maximum width, in characters.
:type n_chars: int or None
"""
self.max_width_chars = n_chars
[docs] def set_line_wrap(self, wrap=None):
"""
Toggles line wrapping within the GtkLabel widget.
``True`` makes it break lines if text exceeds the widget’s size.
``False`` lets the text get cut off by the edge of the widget if it exceeds the widget size.
Note that setting line wrapping to TRUE does not make the label wrap at its parent container’s width,
because GLXCurses widgets conceptually can’t make their requisition depend on the parent container’s size.
For a label that wraps at a specific position, set the label’s width using
GLXCurses.Widget().set_size_request()
:param wrap: True if wrap is enable
:type wrap: bool or None
"""
self.wrap = wrap
[docs] def set_line_wrap_mode(self, wrap_mode=None):
"""
If line wrapping is on (see GLXCurses.Label().set_line_wrap()) this controls how the line wrapping is done.
The default is GLXCurses.GLXC.WRAP_WORD which means wrap on word boundaries.
:param wrap_mode: the line wrapping mode
:type wrap_mode: str or None
"""
self.wrap_mode = wrap_mode
[docs] def set_lines(self, lines=None):
"""
Sets the number of lines to which an ellipsized, wrapping label should be limited.
This has no effect if the label is not wrapping or ellipsized.
Set this to -1 if you don’t want to limit the number of lines.
:param lines: the desired number of lines, or -1
:type lines: int or None
"""
self.lines = lines
[docs] def get_mnemonic_keyval(self):
"""
If the label has been set so that it has an mnemonic key this function returns the keyval used for
the mnemonic accelerator.
If there is no mnemonic set up it returns ``None``.
:return: ord() keyval usable for accelerators, or None
:rtype: int or None
"""
return self.mnemonic_keyval
[docs] def get_selectable(self):
"""
Gets the value set by GLXCurses.Label().set_selectable().
:return: ``True`` if the user can copy text from the label
"""
return self.selectable
[docs] def get_text(self):
"""
Fetches the text from a label widget, as displayed on the screen.
This does not include any embedded underlines indicating mnemonics or markdown.
(See GLXCurses.Label().get_label())
:return: the text in the label widget. This is the internal string used by the label, and must not be modified.
:rtype: str or None
"""
tmp_label = ""
count = 0
while count <= len(self.attributes) - 1:
if not self.attributes[count]["HIDDEN"]:
tmp_label += self.attributes[count]["CHAR"]
count += 1
return tmp_label
[docs] def new_with_mnemonic(self, string=None):
"""
Creates a new GtkLabel, containing the text in str .
If characters in str are preceded by an underscore, they are underlined.
If you need a literal underscore character in a label, use '__' (two underscores).
The first underlined character represents a keyboard accelerator called a mnemonic.
The mnemonic key can be used to activate another widget, chosen automatically,
or explicitly using gtk_label_set_mnemonic_widget().
If GLXCurses.Label().set_mnemonic_widget() is not called,
then the first activatable ancestor of the GLXCurses.Label will be chosen as the mnemonic widget.
For instance, if the label is inside a button or menu item,
the button or menu item will automatically become the mnemonic widget and be activated by the mnemonic.
:param string: The text of the label, with an underscore in front of the mnemonic character.
:type string: str or None
"""
self.label = string
self.use_markdown = False
self.attributes = GLXCurses.TextAttributes().parse(
label=self.label,
markdown_is_used=self.use_markdown,
mnemonic_is_used=True,
mnemonic_use_underline=self.use_underline,
mnemonic_char=self.pattern,
)
if self.parent:
self.mnemonic_widget = self.parent
[docs] def select_region(self, start_offset=None, end_offset=None):
"""
Selects a range of characters in the label, if the label is selectable. See GLXCurses.Label().set_selectable().
If the label is not selectable, this function has no effect.
If ``start_offset`` or ``end_offset`` are -1, then the end of the label will be substituted.
:param start_offset: start offset (in characters not bytes)
:type start_offset: int
:param end_offset: end offset (in characters not bytes)
:type end_offset: int
:raise TypeError: when
"""
if type(start_offset) != int:
raise TypeError("'start_offset' value must be a int type")
if type(end_offset) != int:
raise TypeError("'end_offset' value must be a int type")
if self.selectable:
if start_offset == -1:
self.cursor_position = 0
else:
self.cursor_position = start_offset
if end_offset == -1:
self.selection_bound = len(self.get_text()) - 1
else:
self.selection_bound = end_offset
# The set_use_underline() method sets the "use-underline" property to the value of setting.
# If setting is True,
# an underscore in the text indicates the next character should be used for the mnemonic accelerator key.
[docs] def set_use_underline(self, setting):
self.use_underline = setting
# The get_use_underline() method returns the value of the "use-underline" property.
# If True an embedded underscore in the label indicates the next character is a mnemonic. See set_use_underline().
[docs] def get_use_underline(self):
return self.use_underline
# set_markup_with_mnemonic
# The set_mnemonic_widget() method sets the "mnemonic-widget" property using the value of widget.
# This method associates the label mnemonic with a widget that will be activated
# when the mnemonic accelerator is pressed.
# When the label is inside a widget (like a Button or a Notebook tab) it is automatically associated
# with the correct widget, but sometimes (i.e. when the target is a gtk.Entry next to the label)
# you need to set it explicitly using this function.
# The target widget will be activated by emitting "mnemonic_activate" on it.
# The get_mnemonic_widget() method retrieves the value of the "mnemonic-widget" property which is the target
# of the mnemonic accelerator of this label.
# See set_mnemonic_widget().
[docs] def set_selectable(self, setting=None):
"""
Selectable labels allow the user to select text from the label, for copy-and-paste.
:param setting: ``True`` to allow selecting text in the label
:type setting: bool or None
"""
self.selectable = setting
[docs] def set_text_with_mnemonic(self, string):
"""
Sets the label’s text from the string str .
If characters in str are preceded by an underscore, they are underlined indicating that they represent a
keyboard accelerator called a mnemonic.
The mnemonic key can be used to activate another widget, chosen automatically, or explicitly using
GLXCurses.Label().set_mnemonic_widget().
:param string: a string
:type string: str
"""
self.label = string
self.use_markdown = False
self.attributes = GLXCurses.TextAttributes().parse(
label=self.label,
markdown_is_used=self.use_markdown,
mnemonic_is_used=True,
mnemonic_char=self.pattern,
mnemonic_use_underline=self.use_underline,
)
for item in self.attributes:
if "MNEMONIC" in item and item["MNEMONIC"]:
if "CHAR" in item and item["CHAR"]:
self.mnemonic_keyval = ord(item["CHAR"])
if self.parent:
self.mnemonic_widget = self.parent
else:
self.mnemonic_widget = self
[docs] def update_preferred_sizes(self):
preferred_width = 0
preferred_height = 0
if self.label:
preferred_width += len(self.label)
if self._get_imposed_spacing():
preferred_width += self._get_imposed_spacing() * 2
if self.single_line_mode:
preferred_height += 1
if self._get_imposed_spacing():
preferred_height += self._get_imposed_spacing() * 2
elif self.wrap_mode:
preferred_height += 1
if self._get_imposed_spacing():
preferred_height += self._get_imposed_spacing() * 2
self.preferred_height = preferred_height
self.preferred_width = preferred_width
[docs] def get_justify(self):
"""
Returns the justification of the label.
.. seealso:: \
:func:`Label.set_justify() <GLXCurses.Label.Label.set_justify()>` for set the justification.
:return: the justification
:rtype: GLXCurses.GLXC.Justification
"""
return self.justify
[docs] def get_line_wrap(self):
"""
The get_line_wrap() method returns the value of the "wrap" property.
If "wrap" is True the lines in the label are automatically wrapped. See set_line_wrap().
:return: True if wrap is enable
:rtype: bool
"""
return self.wrap
[docs] def get_width_chars(self):
"""
The get_width_chars() method returns the value of the ``width-chars``
property that specifies the desired width of the label in characters.
:return: width of the label in characters
:rtype: int
"""
return self.width_chars
# The set_single_line_mode() method sets the "single-line-mode" property to the value of single_line_mode.
# If single_line_mode is True the label is in single line mode where the height of the label does not
# depend on the actual text, it is always set to ascent + descent of the font.
[docs] def set_single_line_mode(self, single_line_mode):
self.single_line_mode = bool(single_line_mode)
# The get_single_line_mode() method returns the value of the "single-line-mode" property.
# See the set_single_line_mode() method for more information
[docs] def get_single_line_mode(self):
return bool(self.single_line_mode)
# The get_max_width_chars() method returns the value of the "max-width-chars" property
# which is the desired maximum width of the label in characters.
[docs] def get_max_width_chars(self):
return self.max_width_chars
[docs] def get_line_wrap_mode(self):
return self.wrap_mode
# Internal
def _draw_single_line_mode(self):
# Single line ignore markdown as describe on GTK3 doc
# text = GLXCurses.resize_text(text=self.get_text(), max_width=self.width)
position = 0
item_number = 0
while item_number <= len(self.attributes) - 1:
if not self.attributes[item_number]["HIDDEN"]:
# Draw
self.add_character(
y=GLXCurses.clamp(
value=int(self.height * self.yalign),
smallest=0,
largest=self.height - 1,
),
x=GLXCurses.clamp(
value=int((self.width - len(self.get_text())) * self.xalign)
+ position,
smallest=0,
largest=self.width,
),
character=self.attributes[item_number]["CHAR"],
color=self.color_normal
| self.attributes[item_number]["CURSES_ATTRIBUTES"],
)
position += 1
# Finally
item_number += 1
def _draw_multi_line_mode(self):
max_height = self.height - 1 - (self.ypad * 2)
max_width = self.width - (self.xpad * 2)
line_number = 0
for line in self._textwrap(text=self.label, height=max_height, width=max_width):
char_number = 0
for char in line:
self.add_character(
y=GLXCurses.clamp(
value=int(self.height * self.yalign) + line_number,
smallest=0,
largest=max_height,
),
x=GLXCurses.clamp(
value=int((self.width - len(line)) * self.xalign) + char_number,
smallest=0,
largest=max_width,
),
character=char,
color=self.color_normal,
)
char_number += 1
line_number += 1
def _textwrap(self, text="Hello World!", height=24, width=80):
if self.get_line_wrap():
lines = []
for paragraph in text.split("\n"):
line = []
len_line = 0
if self.get_line_wrap_mode() == GLXCurses.GLXC.WRAP_WORD_CHAR:
# Wrap this text.
wrapped = textwrap.wrap(
paragraph,
width=width,
fix_sentence_endings=True,
break_long_words=True,
break_on_hyphens=True,
)
if len(lines) <= height:
lines += wrapped
elif self.get_line_wrap_mode() == GLXCurses.GLXC.WRAP_CHAR:
if len(paragraph) < width:
if len(lines) < height:
lines.append(paragraph)
else:
if len(lines) < height:
lines += [
paragraph[ind: ind + width]
for ind in range(0, len(paragraph), width)
]
else:
for word in paragraph.split(" "):
len_word = len(word)
if len_line + len_word <= width:
line.append(word)
len_line += len_word + 1
else:
lines.append(" ".join(line))
line = [word]
len_line = len_word + 1
if len(lines) < height:
lines.append(" ".join(line))
return lines
else:
# This is the default display/view
lines = []
for paragraph in text.split("\n"):
if len(paragraph) < width:
if len(lines) < height:
lines.append(paragraph)
else:
if len(lines) < height:
lines.append(paragraph[:width])
return lines
def _check_justification(self, text="Hello World!", width=80):
# Check Justification
self.text_x = 0
if self.justify == GLXCurses.GLXC.JUSTIFY_CENTER:
self.xalign = 0.0
return text.center(width, " ")
elif self.justify == GLXCurses.GLXC.JUSTIFY_LEFT:
self.xalign = 0.0
return "{0:<{1}}".format(text, width)
elif self.justify == GLXCurses.GLXC.JUSTIFY_RIGHT:
self.xalign = 0.0
return "{0:>{1}}".format(text, width)
else:
self.xalign = int((self.width - len(self.get_text())) * self.xalign)
self.yalign = int(self.height * self.yalign)
return self.text_x