summaryrefslogtreecommitdiff
path: root/poezio/windows
diff options
context:
space:
mode:
Diffstat (limited to 'poezio/windows')
-rw-r--r--poezio/windows/base_wins.py2
-rw-r--r--poezio/windows/bookmark_forms.py28
-rw-r--r--poezio/windows/confirm.py2
-rw-r--r--poezio/windows/data_forms.py48
-rw-r--r--poezio/windows/funcs.py2
-rw-r--r--poezio/windows/image.py55
-rw-r--r--poezio/windows/info_bar.py25
-rw-r--r--poezio/windows/info_wins.py112
-rw-r--r--poezio/windows/input_placeholders.py2
-rw-r--r--poezio/windows/inputs.py5
-rw-r--r--poezio/windows/list.py20
-rw-r--r--poezio/windows/misc.py4
-rw-r--r--poezio/windows/muc.py20
-rw-r--r--poezio/windows/roster_win.py81
-rw-r--r--poezio/windows/text_win.py49
15 files changed, 316 insertions, 139 deletions
diff --git a/poezio/windows/base_wins.py b/poezio/windows/base_wins.py
index b14b44c3..6dabd7b8 100644
--- a/poezio/windows/base_wins.py
+++ b/poezio/windows/base_wins.py
@@ -37,6 +37,8 @@ class DummyWin:
class Win:
+ __slots__ = ('_win', 'height', 'width', 'y', 'x')
+
def __init__(self) -> None:
self._win = None
self.height, self.width = 0, 0
diff --git a/poezio/windows/bookmark_forms.py b/poezio/windows/bookmark_forms.py
index b7875e3c..8b9150d6 100644
--- a/poezio/windows/bookmark_forms.py
+++ b/poezio/windows/bookmark_forms.py
@@ -152,6 +152,9 @@ class BookmarkAutojoinWin(FieldInputMixin):
class BookmarksWin(Win):
+ __slots__ = ('scroll_pos', '_current_input', 'current_horizontal_input',
+ '_bookmarks', 'lines')
+
def __init__(self, bookmarks: BookmarkList, height: int, width: int, y: int, x: int) -> None:
self._win = base_wins.TAB_WIN.derwin(height, width, y, x)
self.scroll_pos = 0
@@ -242,9 +245,10 @@ class BookmarksWin(Win):
return
if self.current_input == 0:
return
+ theme = get_theme()
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_NORMAL_TEXT)
+ theme.COLOR_NORMAL_TEXT)
self.current_input -= 1
# Adjust the scroll position if the current_input would be outside
# of the visible area
@@ -253,20 +257,21 @@ class BookmarksWin(Win):
self.refresh()
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ theme.COLOR_SELECTED_ROW)
def go_to_next_horizontal_input(self) -> None:
if not self.lines:
return
+ theme = get_theme()
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_NORMAL_TEXT)
+ theme.COLOR_NORMAL_TEXT)
self.current_horizontal_input += 1
if self.current_horizontal_input > 3:
self.current_horizontal_input = 0
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ theme.COLOR_SELECTED_ROW)
def go_to_next_page(self) -> bool:
if not self.lines:
@@ -275,9 +280,10 @@ class BookmarksWin(Win):
if self.current_input == len(self.lines) - 1:
return False
+ theme = get_theme()
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_NORMAL_TEXT)
+ theme.COLOR_NORMAL_TEXT)
inc = min(self.height, len(self.lines) - self.current_input - 1)
if self.current_input + inc - self.scroll_pos > self.height - 1:
@@ -288,7 +294,7 @@ class BookmarksWin(Win):
self.current_input += inc
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ theme.COLOR_SELECTED_ROW)
return True
def go_to_previous_page(self) -> bool:
@@ -298,9 +304,10 @@ class BookmarksWin(Win):
if self.current_input == 0:
return False
+ theme = get_theme()
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_NORMAL_TEXT)
+ theme.COLOR_NORMAL_TEXT)
dec = min(self.height, self.current_input)
self.current_input -= dec
@@ -311,7 +318,7 @@ class BookmarksWin(Win):
self.refresh()
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ theme.COLOR_SELECTED_ROW)
return True
def go_to_previous_horizontal_input(self) -> None:
@@ -319,13 +326,14 @@ class BookmarksWin(Win):
return
if self.current_horizontal_input == 0:
return
+ theme = get_theme()
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_NORMAL_TEXT)
+ theme.COLOR_NORMAL_TEXT)
self.current_horizontal_input -= 1
self.lines[self.current_input][
self.current_horizontal_input].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ theme.COLOR_SELECTED_ROW)
def on_input(self, key: str) -> None:
if not self.lines:
diff --git a/poezio/windows/confirm.py b/poezio/windows/confirm.py
index 65878509..0a8de67b 100644
--- a/poezio/windows/confirm.py
+++ b/poezio/windows/confirm.py
@@ -4,6 +4,8 @@ from poezio.theming import get_theme, to_curses_attr
class Dialog(Win):
+ __slots__ = ('text', 'accept', 'critical')
+
str_accept = " Accept "
str_refuse = " Reject "
diff --git a/poezio/windows/data_forms.py b/poezio/windows/data_forms.py
index dc954bd7..3ec44b97 100644
--- a/poezio/windows/data_forms.py
+++ b/poezio/windows/data_forms.py
@@ -20,6 +20,9 @@ class FieldInput:
'windows' library.
"""
+ # XXX: This conflicts with Win in the FieldInputMixin.
+ #__slots__ = ('_field', 'color')
+
def __init__(self, field):
self._field = field
self.color = get_theme().COLOR_NORMAL_TEXT
@@ -47,6 +50,8 @@ class FieldInput:
class FieldInputMixin(FieldInput, Win):
"Mix both FieldInput and Win"
+ __slots__ = ()
+
def __init__(self, field):
FieldInput.__init__(self, field)
Win.__init__(self)
@@ -60,6 +65,8 @@ class FieldInputMixin(FieldInput, Win):
class ColoredLabel(Win):
+ __slots__ = ('text', 'color')
+
def __init__(self, text):
self.text = text
self.color = get_theme().COLOR_NORMAL_TEXT
@@ -85,6 +92,8 @@ class DummyInput(FieldInputMixin):
Used for fields that do not require any input ('fixed')
"""
+ __slots__ = ()
+
def __init__(self, field):
FieldInputMixin.__init__(self, field)
@@ -99,6 +108,8 @@ class DummyInput(FieldInputMixin):
class BooleanWin(FieldInputMixin):
+ __slots__ = ('last_key', 'value')
+
def __init__(self, field):
FieldInputMixin.__init__(self, field)
self.last_key = 'KEY_RIGHT'
@@ -133,6 +144,8 @@ class BooleanWin(FieldInputMixin):
class TextMultiWin(FieldInputMixin):
+ __slots__ = ('options', 'val_pos', 'edition_input')
+
def __init__(self, field):
FieldInputMixin.__init__(self, field)
options = field.get_value()
@@ -212,6 +225,8 @@ class TextMultiWin(FieldInputMixin):
class ListMultiWin(FieldInputMixin):
+ __slots__ = ('options', 'val_pos')
+
def __init__(self, field):
FieldInputMixin.__init__(self, field)
values = field.get_value() or []
@@ -261,6 +276,8 @@ class ListMultiWin(FieldInputMixin):
class ListSingleWin(FieldInputMixin):
+ __slots__ = ('options', 'val_pos')
+
def __init__(self, field):
FieldInputMixin.__init__(self, field)
# the option list never changes
@@ -306,6 +323,8 @@ class ListSingleWin(FieldInputMixin):
class TextSingleWin(FieldInputMixin, Input):
+ __slots__ = ('text', 'pos')
+
def __init__(self, field):
FieldInputMixin.__init__(self, field)
Input.__init__(self)
@@ -323,6 +342,8 @@ class TextSingleWin(FieldInputMixin, Input):
class TextPrivateWin(TextSingleWin):
+ __slots__ = ()
+
def __init__(self, field):
TextSingleWin.__init__(self, field)
@@ -352,6 +373,8 @@ class FormWin:
On resize, move and resize all the subwin and define how the text will be written
On refresh, write all the text, and refresh all the subwins
"""
+ __slots__ = ('_win', 'height', 'width', '_form', 'scroll_pos', 'current_input', 'inputs')
+
input_classes = {
'boolean': BooleanWin,
'fixed': DummyInput,
@@ -415,10 +438,11 @@ class FormWin:
return
if self.current_input == len(self.inputs) - 1:
return
+ theme = get_theme()
self.inputs[self.current_input]['input'].set_color(
- get_theme().COLOR_NORMAL_TEXT)
+ theme.COLOR_NORMAL_TEXT)
self.inputs[self.current_input]['label'].set_color(
- get_theme().COLOR_NORMAL_TEXT)
+ theme.COLOR_NORMAL_TEXT)
self.current_input += 1
jump = 0
while self.current_input + jump != len(
@@ -437,19 +461,20 @@ class FormWin:
self.scroll_pos += 1
self.refresh()
self.inputs[self.current_input]['input'].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ theme.COLOR_SELECTED_ROW)
self.inputs[self.current_input]['label'].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ theme.COLOR_SELECTED_ROW)
def go_to_previous_input(self):
if not self.inputs:
return
if self.current_input == 0:
return
+ theme = get_theme()
self.inputs[self.current_input]['input'].set_color(
- get_theme().COLOR_NORMAL_TEXT)
+ theme.COLOR_NORMAL_TEXT)
self.inputs[self.current_input]['label'].set_color(
- get_theme().COLOR_NORMAL_TEXT)
+ theme.COLOR_NORMAL_TEXT)
self.current_input -= 1
jump = 0
while self.current_input - jump > 0 and self.inputs[self.current_input
@@ -466,9 +491,9 @@ class FormWin:
self.refresh()
self.current_input -= jump
self.inputs[self.current_input]['input'].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ theme.COLOR_SELECTED_ROW)
self.inputs[self.current_input]['label'].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ theme.COLOR_SELECTED_ROW)
def on_input(self, key, raw=False):
if not self.inputs:
@@ -498,11 +523,10 @@ class FormWin:
inp['input'].refresh()
inp['label'].refresh()
if self.inputs and self.current_input < self.height - 1:
- self.inputs[self.current_input]['input'].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ color = get_theme().COLOR_SELECTED_ROW
+ self.inputs[self.current_input]['input'].set_color(color)
self.inputs[self.current_input]['input'].refresh()
- self.inputs[self.current_input]['label'].set_color(
- get_theme().COLOR_SELECTED_ROW)
+ self.inputs[self.current_input]['label'].set_color(color)
self.inputs[self.current_input]['label'].refresh()
def refresh_current_input(self):
diff --git a/poezio/windows/funcs.py b/poezio/windows/funcs.py
index 69edace2..22977374 100644
--- a/poezio/windows/funcs.py
+++ b/poezio/windows/funcs.py
@@ -22,7 +22,7 @@ def find_first_format_char(text: str,
return pos
-def truncate_nick(nick: str, size=10) -> str:
+def truncate_nick(nick: Optional[str], size=10) -> Optional[str]:
if size < 1:
size = 1
if nick and len(nick) > size:
diff --git a/poezio/windows/image.py b/poezio/windows/image.py
index 309fe0e6..96636ec7 100644
--- a/poezio/windows/image.py
+++ b/poezio/windows/image.py
@@ -9,8 +9,20 @@ try:
from PIL import Image
HAS_PIL = True
except ImportError:
+ class Image:
+ class Image:
+ pass
HAS_PIL = False
+try:
+ import gi
+ gi.require_version('Rsvg', '2.0')
+ from gi.repository import Rsvg
+ import cairo
+ HAS_RSVG = True
+except (ImportError, ValueError):
+ HAS_RSVG = False
+
from poezio.windows.base_wins import Win
from poezio.theming import get_theme, to_curses_attr
from poezio.xhtml import _parse_css_color
@@ -19,13 +31,45 @@ from poezio.config import config
from typing import Tuple, Optional, Callable
+MAX_SIZE = 16
+
+
+def render_svg(svg: bytes) -> Optional[Image.Image]:
+ if not HAS_RSVG:
+ return None
+ try:
+ handle = Rsvg.Handle.new_from_data(svg)
+ dimensions = handle.get_dimensions()
+ biggest_dimension = max(dimensions.width, dimensions.height)
+ scale = MAX_SIZE / biggest_dimension
+ translate_x = (biggest_dimension - dimensions.width) / 2
+ translate_y = (biggest_dimension - dimensions.height) / 2
+
+ surface = cairo.ImageSurface(cairo.Format.ARGB32, MAX_SIZE, MAX_SIZE)
+ context = cairo.Context(surface)
+ context.scale(scale, scale)
+ context.translate(translate_x, translate_y)
+ handle.render_cairo(context)
+ data = surface.get_data()
+ image = Image.frombytes('RGBA', (MAX_SIZE, MAX_SIZE), data.tobytes())
+ # This is required because Cairo uses a BGRA (in host endianess)
+ # format, and PIL an ABGR (in byte order) format. Yes, this is
+ # confusing.
+ b, g, r, a = image.split()
+ return Image.merge('RGB', (r, g, b))
+ except Exception:
+ return None
+
+
class ImageWin(Win):
"""
A window which contains either an image or a border.
"""
+ __slots__ = ('_image', '_display_avatar')
+
def __init__(self) -> None:
- self._image = None # type: Optional[Image]
+ self._image = None # type: Optional[Image.Image]
Win.__init__(self)
if config.get('image_use_half_blocks'):
self._display_avatar = self._display_avatar_half_blocks # type: Callable[[int, int], None]
@@ -43,7 +87,14 @@ class ImageWin(Win):
if data is not None and HAS_PIL:
image_file = BytesIO(data)
try:
- image = Image.open(image_file)
+ try:
+ image = Image.open(image_file)
+ except OSError:
+ # TODO: Make the caller pass the MIME type, so we don’t
+ # have to try all renderers like that.
+ image = render_svg(data)
+ if image is None:
+ raise
except OSError:
self._display_border()
else:
diff --git a/poezio/windows/info_bar.py b/poezio/windows/info_bar.py
index 96382d0f..ac900103 100644
--- a/poezio/windows/info_bar.py
+++ b/poezio/windows/info_bar.py
@@ -16,6 +16,8 @@ from poezio.theming import get_theme, to_curses_attr
class GlobalInfoBar(Win):
+ __slots__ = ('core')
+
def __init__(self, core) -> None:
Win.__init__(self)
self.core = core
@@ -23,8 +25,9 @@ class GlobalInfoBar(Win):
def refresh(self) -> None:
log.debug('Refresh: %s', self.__class__.__name__)
self._win.erase()
+ theme = get_theme()
self.addstr(0, 0, "[",
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_INFORMATION_BAR))
show_names = config.get('show_tab_names')
show_nums = config.get('show_tab_numbers')
@@ -35,7 +38,7 @@ class GlobalInfoBar(Win):
if not tab:
continue
color = tab.color
- if not show_inactive and color is get_theme().COLOR_TAB_NORMAL:
+ if not show_inactive and color is theme.COLOR_TAB_NORMAL:
continue
try:
if show_nums or not show_names:
@@ -49,20 +52,22 @@ class GlobalInfoBar(Win):
else:
self.addstr("%s" % tab.name, to_curses_attr(color))
self.addstr("|",
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_INFORMATION_BAR))
except: # end of line
break
(y, x) = self._win.getyx()
self.addstr(y, x - 1, '] ',
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_INFORMATION_BAR))
(y, x) = self._win.getyx()
remaining_size = self.width - x
self.addnstr(' ' * remaining_size, remaining_size,
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_INFORMATION_BAR))
self._refresh()
class VerticalGlobalInfoBar(Win):
+ __slots__ = ('core')
+
def __init__(self, core, scr) -> None:
Win.__init__(self)
self.core = core
@@ -72,17 +77,17 @@ class VerticalGlobalInfoBar(Win):
height, width = self._win.getmaxyx()
self._win.erase()
sorted_tabs = [tab for tab in self.core.tabs if tab]
+ theme = get_theme()
if not config.get('show_inactive_tabs'):
sorted_tabs = [
tab for tab in sorted_tabs
- if tab.vertical_color != get_theme().COLOR_VERTICAL_TAB_NORMAL
+ if tab.vertical_color != theme.COLOR_VERTICAL_TAB_NORMAL
]
nb_tabs = len(sorted_tabs)
use_nicks = config.get('use_tab_nicks')
if nb_tabs >= height:
for y, tab in enumerate(sorted_tabs):
- if tab.vertical_color == get_theme(
- ).COLOR_VERTICAL_TAB_CURRENT:
+ if tab.vertical_color == theme.COLOR_VERTICAL_TAB_CURRENT:
pos = y
break
# center the current tab as much as possible
@@ -98,14 +103,14 @@ class VerticalGlobalInfoBar(Win):
if asc_sort:
y = height - y - 1
self.addstr(y, 0, "%2d" % tab.nb,
- to_curses_attr(get_theme().COLOR_VERTICAL_TAB_NUMBER))
+ to_curses_attr(theme.COLOR_VERTICAL_TAB_NUMBER))
self.addstr('.')
if use_nicks:
self.addnstr("%s" % tab.get_nick(), width - 4,
to_curses_attr(color))
else:
self.addnstr("%s" % tab.name, width - 4, to_curses_attr(color))
- separator = to_curses_attr(get_theme().COLOR_VERTICAL_SEPARATOR)
+ separator = to_curses_attr(theme.COLOR_VERTICAL_SEPARATOR)
self._win.attron(separator)
self._win.vline(0, width - 1, curses.ACS_VLINE, height)
self._win.attroff(separator)
diff --git a/poezio/windows/info_wins.py b/poezio/windows/info_wins.py
index 27f9e1cf..3a8d1863 100644
--- a/poezio/windows/info_wins.py
+++ b/poezio/windows/info_wins.py
@@ -20,6 +20,8 @@ class InfoWin(Win):
MucInfoWin, etc. Provides some useful methods.
"""
+ __slots__ = ()
+
def __init__(self):
Win.__init__(self)
@@ -40,6 +42,8 @@ class XMLInfoWin(InfoWin):
Info about the latest xml filter used and the state of the buffer.
"""
+ __slots__ = ()
+
def __init__(self):
InfoWin.__init__(self)
@@ -63,6 +67,8 @@ class PrivateInfoWin(InfoWin):
about the MUC user we are talking to
"""
+ __slots__ = ()
+
def __init__(self):
InfoWin.__init__(self)
@@ -81,16 +87,17 @@ class PrivateInfoWin(InfoWin):
Write all information added by plugins by getting the
value returned by the callbacks.
"""
- for key in information:
- self.addstr(information[key](jid),
+ for plugin in information.values():
+ self.addstr(plugin(jid),
to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
def write_room_name(self, name):
jid = safeJID(name)
room_name, nick = jid.bare, jid.resource
- self.addstr(nick, to_curses_attr(get_theme().COLOR_PRIVATE_NAME))
+ theme = get_theme()
+ self.addstr(nick, to_curses_attr(theme.COLOR_PRIVATE_NAME))
txt = ' from room %s' % room_name
- self.addstr(txt, to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.addstr(txt, to_curses_attr(theme.COLOR_INFORMATION_BAR))
def write_chatstate(self, state):
if state:
@@ -104,6 +111,8 @@ class MucListInfoWin(InfoWin):
about the muc server being listed
"""
+ __slots__ = ('message')
+
def __init__(self, message=''):
InfoWin.__init__(self)
self.message = message
@@ -111,15 +120,16 @@ class MucListInfoWin(InfoWin):
def refresh(self, name=None, window=None):
log.debug('Refresh: %s', self.__class__.__name__)
self._win.erase()
+ theme = get_theme()
if name:
self.addstr(name,
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_INFORMATION_BAR))
else:
self.addstr(self.message,
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_INFORMATION_BAR))
if window:
self.print_scroll_position(window)
- self.finish_line(get_theme().COLOR_INFORMATION_BAR)
+ self.finish_line(theme.COLOR_INFORMATION_BAR)
self._refresh()
@@ -129,6 +139,8 @@ class ConversationInfoWin(InfoWin):
about the user we are talking to
"""
+ __slots__ = ()
+
def __init__(self):
InfoWin.__init__(self)
@@ -166,9 +178,9 @@ class ConversationInfoWin(InfoWin):
Write all information added by plugins by getting the
value returned by the callbacks.
"""
- for key in information:
- self.addstr(information[key](jid),
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ color = to_curses_attr(get_theme().COLOR_INFORMATION_BAR)
+ for plugin in information.values():
+ self.addstr(plugin(jid), color)
def write_resource_information(self, resource):
"""
@@ -178,38 +190,40 @@ class ConversationInfoWin(InfoWin):
presence = "unavailable"
else:
presence = resource.presence
- color = get_theme().color_show(presence)
+ theme = get_theme()
+ color = theme.color_show(presence)
if not presence:
- presence = get_theme().CHAR_STATUS
- self.addstr('[', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ presence = theme.CHAR_STATUS
+ self.addstr('[', to_curses_attr(theme.COLOR_INFORMATION_BAR))
self.addstr(presence, to_curses_attr(color))
if resource and resource.status:
shortened = resource.status[:20] + (resource.status[:20] and '…')
self.addstr(' %s' % shortened,
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
- self.addstr(']', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_INFORMATION_BAR))
+ self.addstr(']', to_curses_attr(theme.COLOR_INFORMATION_BAR))
def write_contact_information(self, contact):
"""
Write the information about the contact
"""
+ color = to_curses_attr(get_theme().COLOR_INFORMATION_BAR)
if not contact:
- self.addstr("(contact not in roster)",
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.addstr("(contact not in roster)", color)
return
display_name = contact.name
if display_name:
- self.addstr('%s ' % (display_name),
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.addstr('%s ' % (display_name), color)
def write_contact_jid(self, jid):
"""
Just write the jid that we are talking to
"""
- self.addstr('[', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ theme = get_theme()
+ color = to_curses_attr(theme.COLOR_INFORMATION_BAR)
+ self.addstr('[', color)
self.addstr(jid.full,
- to_curses_attr(get_theme().COLOR_CONVERSATION_NAME))
- self.addstr('] ', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_CONVERSATION_NAME))
+ self.addstr('] ', color)
def write_chatstate(self, state):
if state:
@@ -218,20 +232,24 @@ class ConversationInfoWin(InfoWin):
class DynamicConversationInfoWin(ConversationInfoWin):
+ __slots__ = ()
+
def write_contact_jid(self, jid):
"""
Just displays the resource in an other color
"""
log.debug("write_contact_jid DynamicConversationInfoWin, jid: %s",
jid.resource)
- self.addstr('[', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ theme = get_theme()
+ color = to_curses_attr(theme.COLOR_INFORMATION_BAR)
+ self.addstr('[', color)
self.addstr(jid.bare,
- to_curses_attr(get_theme().COLOR_CONVERSATION_NAME))
+ to_curses_attr(theme.COLOR_CONVERSATION_NAME))
if jid.resource:
self.addstr(
"/%s" % (jid.resource, ),
- to_curses_attr(get_theme().COLOR_CONVERSATION_RESOURCE))
- self.addstr('] ', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_CONVERSATION_RESOURCE))
+ self.addstr('] ', color)
class MucInfoWin(InfoWin):
@@ -240,10 +258,12 @@ class MucInfoWin(InfoWin):
about the MUC we are viewing
"""
+ __slots__ = ()
+
def __init__(self):
InfoWin.__init__(self)
- def refresh(self, room, window=None, user=None):
+ def refresh(self, room, window=None, user=None, information=None):
log.debug('Refresh: %s', self.__class__.__name__)
self._win.erase()
self.write_room_name(room)
@@ -251,23 +271,38 @@ class MucInfoWin(InfoWin):
self.write_own_nick(room)
self.write_disconnected(room)
self.write_role(room, user)
+ if information:
+ self.write_additional_information(information, room.name)
if window:
self.print_scroll_position(window)
self.finish_line(get_theme().COLOR_INFORMATION_BAR)
self._refresh()
+ def write_additional_information(self, information, jid):
+ """
+ Write all information added by plugins by getting the
+ value returned by the callbacks.
+ """
+ color = to_curses_attr(get_theme().COLOR_INFORMATION_BAR)
+ for plugin in information.values():
+ self.addstr(plugin(jid), color)
+
def write_room_name(self, room):
- self.addstr('[', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ theme = get_theme()
+ color = to_curses_attr(theme.COLOR_INFORMATION_BAR)
+ self.addstr('[', color)
self.addstr(room.name,
- to_curses_attr(get_theme().COLOR_GROUPCHAT_NAME))
- self.addstr(']', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_GROUPCHAT_NAME))
+ self.addstr(']', color)
def write_participants_number(self, room):
- self.addstr('{', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ theme = get_theme()
+ color = to_curses_attr(theme.COLOR_INFORMATION_BAR)
+ self.addstr('{', color)
self.addstr(
str(len(room.users)),
- to_curses_attr(get_theme().COLOR_GROUPCHAT_NAME))
- self.addstr('} ', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_GROUPCHAT_NAME))
+ self.addstr('} ', color)
def write_disconnected(self, room):
"""
@@ -306,6 +341,8 @@ class ConversationStatusMessageWin(InfoWin):
The upper bar displaying the status message of the contact
"""
+ __slots__ = ()
+
def __init__(self):
InfoWin.__init__(self)
@@ -331,6 +368,8 @@ class ConversationStatusMessageWin(InfoWin):
class BookmarksInfoWin(InfoWin):
+ __slots__ = ()
+
def __init__(self):
InfoWin.__init__(self)
@@ -347,6 +386,8 @@ class BookmarksInfoWin(InfoWin):
class ConfirmStatusWin(Win):
+ __slots__ = ('text', 'critical')
+
def __init__(self, text, critical=False):
Win.__init__(self)
self.text = text
@@ -355,10 +396,11 @@ class ConfirmStatusWin(Win):
def refresh(self):
log.debug('Refresh: %s', self.__class__.__name__)
self._win.erase()
+ theme = get_theme()
if self.critical:
- color = get_theme().COLOR_WARNING_PROMPT
+ color = theme.COLOR_WARNING_PROMPT
else:
- color = get_theme().COLOR_INFORMATION_BAR
+ color = theme.COLOR_INFORMATION_BAR
c_color = to_curses_attr(color)
self.addstr(self.text, c_color)
self.finish_line(color)
diff --git a/poezio/windows/input_placeholders.py b/poezio/windows/input_placeholders.py
index c5656f72..4d414636 100644
--- a/poezio/windows/input_placeholders.py
+++ b/poezio/windows/input_placeholders.py
@@ -19,6 +19,8 @@ class HelpText(Win):
command mode.
"""
+ __slots__ = ('txt')
+
def __init__(self, text: str = '') -> None:
Win.__init__(self)
self.txt = text # type: str
diff --git a/poezio/windows/inputs.py b/poezio/windows/inputs.py
index 6b0bc798..c0c73419 100644
--- a/poezio/windows/inputs.py
+++ b/poezio/windows/inputs.py
@@ -32,6 +32,9 @@ class Input(Win):
passing the list of items that can be used to complete. The completion can be used
in a very flexible way.
"""
+ __slots__ = ('key_func', 'text', 'pos', 'view_pos', 'on_input', 'color',
+ 'last_completion', 'hit_list')
+
text_attributes = 'bou1234567ti'
clipboard = '' # A common clipboard for all the inputs, this makes
@@ -586,6 +589,8 @@ class HistoryInput(Input):
An input with colors and stuff, plus an history
^R allows to search inside the history (as in a shell)
"""
+ __slots__ = ('help_message', 'histo_pos', 'current_completed', 'search')
+
history = [] # type: List[str]
def __init__(self) -> None:
diff --git a/poezio/windows/list.py b/poezio/windows/list.py
index b24b8aea..350255c6 100644
--- a/poezio/windows/list.py
+++ b/poezio/windows/list.py
@@ -19,6 +19,9 @@ class ListWin(Win):
scrolled up and down, with one selected line at a time
"""
+ __slots__ = ('_columns', '_columns_sizes', 'sorted_by', 'lines',
+ '_selected_row', '_starting_pos')
+
def __init__(self, columns: Dict[str, int], with_headers: bool = True) -> None:
Win.__init__(self)
self._columns = columns # type: Dict[str, int]
@@ -91,6 +94,7 @@ class ListWin(Win):
log.debug('Refresh: %s', self.__class__.__name__)
self._win.erase()
lines = self.lines[self._starting_pos:self._starting_pos + self.height]
+ color = to_curses_attr(get_theme().COLOR_INFORMATION_BAR)
for y, line in enumerate(lines):
x = 0
for col in self._columns.items():
@@ -103,9 +107,7 @@ class ListWin(Win):
if not txt:
continue
if line is self.lines[self._selected_row]:
- self.addstr(
- y, x, txt[:size],
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.addstr(y, x, txt[:size], color)
else:
self.addstr(y, x, txt[:size])
x += size
@@ -165,6 +167,9 @@ class ColumnHeaderWin(Win):
A class displaying the column's names
"""
+ __slots__ = ('_columns', '_columns_sizes', '_column_sel', '_column_order',
+ '_column_order_asc')
+
def __init__(self, columns: List[str]) -> None:
Win.__init__(self)
self._columns = columns
@@ -183,23 +188,24 @@ class ColumnHeaderWin(Win):
log.debug('Refresh: %s', self.__class__.__name__)
self._win.erase()
x = 0
+ theme = get_theme()
for col in self._columns:
txt = col
if col in self._column_order:
if self._column_order_asc:
- txt += get_theme().CHAR_COLUMN_ASC
+ txt += theme.CHAR_COLUMN_ASC
else:
- txt += get_theme().CHAR_COLUMN_DESC
+ txt += theme.CHAR_COLUMN_DESC
#⇓⇑↑↓⇧⇩▲▼
size = self._columns_sizes[col]
txt += ' ' * (size - len(txt))
if col in self._column_sel:
self.addstr(
0, x, txt,
- to_curses_attr(get_theme().COLOR_COLUMN_HEADER_SEL))
+ to_curses_attr(theme.COLOR_COLUMN_HEADER_SEL))
else:
self.addstr(0, x, txt,
- to_curses_attr(get_theme().COLOR_COLUMN_HEADER))
+ to_curses_attr(theme.COLOR_COLUMN_HEADER))
x += size
self._refresh()
diff --git a/poezio/windows/misc.py b/poezio/windows/misc.py
index e6596622..6c04b814 100644
--- a/poezio/windows/misc.py
+++ b/poezio/windows/misc.py
@@ -19,6 +19,8 @@ class VerticalSeparator(Win):
refreshed only on resize, but never on refresh, for efficiency
"""
+ __slots__ = ()
+
def rewrite_line(self) -> None:
self._win.vline(0, 0, curses.ACS_VLINE, self.height,
to_curses_attr(get_theme().COLOR_VERTICAL_SEPARATOR))
@@ -30,6 +32,8 @@ class VerticalSeparator(Win):
class SimpleTextWin(Win):
+ __slots__ = ('_text', 'built_lines')
+
def __init__(self, text) -> None:
Win.__init__(self)
self._text = text
diff --git a/poezio/windows/muc.py b/poezio/windows/muc.py
index 3e52f63d..951940e1 100644
--- a/poezio/windows/muc.py
+++ b/poezio/windows/muc.py
@@ -28,6 +28,8 @@ def userlist_to_cache(userlist: List[User]) -> List[CachedUser]:
class UserList(Win):
+ __slots__ = ('pos', 'cache')
+
def __init__(self) -> None:
Win.__init__(self)
self.pos = 0
@@ -108,15 +110,16 @@ class UserList(Win):
self.addstr(y, 1, symbol, to_curses_attr(color))
def draw_status_chatstate(self, y: int, user: User) -> None:
- show_col = get_theme().color_show(user.show)
+ theme = get_theme()
+ show_col = theme.color_show(user.show)
if user.chatstate == 'composing':
- char = get_theme().CHAR_CHATSTATE_COMPOSING
+ char = theme.CHAR_CHATSTATE_COMPOSING
elif user.chatstate == 'active':
- char = get_theme().CHAR_CHATSTATE_ACTIVE
+ char = theme.CHAR_CHATSTATE_ACTIVE
elif user.chatstate == 'paused':
- char = get_theme().CHAR_CHATSTATE_PAUSED
+ char = theme.CHAR_CHATSTATE_PAUSED
else:
- char = get_theme().CHAR_STATUS
+ char = theme.CHAR_STATUS
self.addstr(y, 0, char, to_curses_attr(show_col))
def resize(self, height: int, width: int, y: int, x: int) -> None:
@@ -128,23 +131,26 @@ class UserList(Win):
class Topic(Win):
+ __slots__ = ('_message')
+
def __init__(self) -> None:
Win.__init__(self)
self._message = ''
def refresh(self, topic: Optional[str] = None) -> None:
log.debug('Refresh: %s', self.__class__.__name__)
+ theme = get_theme()
self._win.erase()
if topic is not None:
msg = topic[:self.width - 1]
else:
msg = self._message[:self.width - 1]
- self.addstr(0, 0, msg, to_curses_attr(get_theme().COLOR_TOPIC_BAR))
+ self.addstr(0, 0, msg, to_curses_attr(theme.COLOR_TOPIC_BAR))
_, x = self._win.getyx()
remaining_size = self.width - x
if remaining_size:
self.addnstr(' ' * remaining_size, remaining_size,
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ to_curses_attr(theme.COLOR_INFORMATION_BAR))
self._refresh()
def set_message(self, message) -> None:
diff --git a/poezio/windows/roster_win.py b/poezio/windows/roster_win.py
index 3497e342..2efdd324 100644
--- a/poezio/windows/roster_win.py
+++ b/poezio/windows/roster_win.py
@@ -20,6 +20,8 @@ Row = Union[RosterGroup, Contact]
class RosterWin(Win):
+ __slots__ = ('pos', 'start_pos', 'selected_row', 'roster_cache')
+
def __init__(self) -> None:
Win.__init__(self)
self.pos = 0 # cursor position in the contact list
@@ -193,18 +195,20 @@ class RosterWin(Win):
"""
The header at the top
"""
+ color = get_theme().COLOR_INFORMATION_BAR
self.addstr(
'Roster: %s/%s contacts' % (roster.get_nb_connected_contacts(),
len(roster)),
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
- self.finish_line(get_theme().COLOR_INFORMATION_BAR)
+ to_curses_attr(color))
+ self.finish_line(color)
def draw_group(self, y: int, group: RosterGroup, colored: bool) -> None:
"""
Draw a groupname on a line
"""
+ color = to_curses_attr(get_theme().COLOR_SELECTED_ROW)
if colored:
- self._win.attron(to_curses_attr(get_theme().COLOR_SELECTED_ROW))
+ self._win.attron(color)
if group.folded:
self.addstr(y, 0, '[+] ')
else:
@@ -215,7 +219,7 @@ class RosterWin(Win):
self.truncate_name(group.name,
len(contacts) + 4) + contacts)
if colored:
- self._win.attroff(to_curses_attr(get_theme().COLOR_SELECTED_ROW))
+ self._win.attroff(color)
self.finish_line()
def truncate_name(self, name, added):
@@ -261,17 +265,17 @@ class RosterWin(Win):
added += 4
if contact.ask:
- added += len(get_theme().CHAR_ROSTER_ASKED)
+ added += len(theme.CHAR_ROSTER_ASKED)
if show_s2s_errors and contact.error:
- added += len(get_theme().CHAR_ROSTER_ERROR)
+ added += len(theme.CHAR_ROSTER_ERROR)
if contact.tune:
- added += len(get_theme().CHAR_ROSTER_TUNE)
+ added += len(theme.CHAR_ROSTER_TUNE)
if contact.mood:
- added += len(get_theme().CHAR_ROSTER_MOOD)
+ added += len(theme.CHAR_ROSTER_MOOD)
if contact.activity:
- added += len(get_theme().CHAR_ROSTER_ACTIVITY)
+ added += len(theme.CHAR_ROSTER_ACTIVITY)
if contact.gaming:
- added += len(get_theme().CHAR_ROSTER_GAMING)
+ added += len(theme.CHAR_ROSTER_GAMING)
if show_roster_sub in ('all', 'incomplete', 'to', 'from', 'both',
'none'):
added += len(
@@ -289,7 +293,7 @@ class RosterWin(Win):
if colored:
self.addstr(display_name,
- to_curses_attr(get_theme().COLOR_SELECTED_ROW))
+ to_curses_attr(theme.COLOR_SELECTED_ROW))
else:
self.addstr(display_name)
@@ -300,34 +304,35 @@ class RosterWin(Win):
contact.subscription, keep=show_roster_sub),
to_curses_attr(theme.COLOR_ROSTER_SUBSCRIPTION))
if contact.ask:
- self.addstr(get_theme().CHAR_ROSTER_ASKED,
- to_curses_attr(get_theme().COLOR_IMPORTANT_TEXT))
+ self.addstr(theme.CHAR_ROSTER_ASKED,
+ to_curses_attr(theme.COLOR_IMPORTANT_TEXT))
if show_s2s_errors and contact.error:
- self.addstr(get_theme().CHAR_ROSTER_ERROR,
- to_curses_attr(get_theme().COLOR_ROSTER_ERROR))
+ self.addstr(theme.CHAR_ROSTER_ERROR,
+ to_curses_attr(theme.COLOR_ROSTER_ERROR))
if contact.tune:
- self.addstr(get_theme().CHAR_ROSTER_TUNE,
- to_curses_attr(get_theme().COLOR_ROSTER_TUNE))
+ self.addstr(theme.CHAR_ROSTER_TUNE,
+ to_curses_attr(theme.COLOR_ROSTER_TUNE))
if contact.activity:
- self.addstr(get_theme().CHAR_ROSTER_ACTIVITY,
- to_curses_attr(get_theme().COLOR_ROSTER_ACTIVITY))
+ self.addstr(theme.CHAR_ROSTER_ACTIVITY,
+ to_curses_attr(theme.COLOR_ROSTER_ACTIVITY))
if contact.mood:
- self.addstr(get_theme().CHAR_ROSTER_MOOD,
- to_curses_attr(get_theme().COLOR_ROSTER_MOOD))
+ self.addstr(theme.CHAR_ROSTER_MOOD,
+ to_curses_attr(theme.COLOR_ROSTER_MOOD))
if contact.gaming:
- self.addstr(get_theme().CHAR_ROSTER_GAMING,
- to_curses_attr(get_theme().COLOR_ROSTER_GAMING))
+ self.addstr(theme.CHAR_ROSTER_GAMING,
+ to_curses_attr(theme.COLOR_ROSTER_GAMING))
self.finish_line()
def draw_resource_line(self, y: int, resource: Resource, colored: bool) -> None:
"""
Draw a specific resource line
"""
- color = get_theme().color_show(resource.presence)
- self.addstr(y, 4, get_theme().CHAR_STATUS, to_curses_attr(color))
+ theme = get_theme()
+ color = theme.color_show(resource.presence)
+ self.addstr(y, 4, theme.CHAR_STATUS, to_curses_attr(color))
if colored:
self.addstr(y, 8, self.truncate_name(str(resource.jid), 6),
- to_curses_attr(get_theme().COLOR_SELECTED_ROW))
+ to_curses_attr(theme.COLOR_SELECTED_ROW))
else:
self.addstr(y, 8, self.truncate_name(str(resource.jid), 6))
self.finish_line()
@@ -342,10 +347,13 @@ class RosterWin(Win):
class ContactInfoWin(Win):
+ __slots__ = ()
+
def draw_contact_info(self, contact: Contact) -> None:
"""
draw the contact information
"""
+ theme = get_theme()
resource = contact.get_highest_priority_resource()
if contact:
jid = str(contact.bare_jid)
@@ -361,8 +369,8 @@ class ContactInfoWin(Win):
self.addstr(0, 0, '%s (%s)' % (
jid,
presence,
- ), to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
- self.finish_line(get_theme().COLOR_INFORMATION_BAR)
+ ), to_curses_attr(theme.COLOR_INFORMATION_BAR))
+ self.finish_line(theme.COLOR_INFORMATION_BAR)
i += 1
self.addstr(i, 0, 'Subscription: %s' % (contact.subscription, ))
self.finish_line()
@@ -370,7 +378,7 @@ class ContactInfoWin(Win):
if contact.ask:
if contact.ask == 'asked':
self.addstr(i, 0, 'Ask: %s' % (contact.ask, ),
- to_curses_attr(get_theme().COLOR_IMPORTANT_TEXT))
+ to_curses_attr(theme.COLOR_IMPORTANT_TEXT))
else:
self.addstr(i, 0, 'Ask: %s' % (contact.ask, ))
self.finish_line()
@@ -382,33 +390,33 @@ class ContactInfoWin(Win):
if contact.error:
self.addstr(i, 0, 'Error: %s' % contact.error,
- to_curses_attr(get_theme().COLOR_ROSTER_ERROR))
+ to_curses_attr(theme.COLOR_ROSTER_ERROR))
self.finish_line()
i += 1
if contact.tune:
self.addstr(i, 0,
'Tune: %s' % common.format_tune_string(contact.tune),
- to_curses_attr(get_theme().COLOR_NORMAL_TEXT))
+ to_curses_attr(theme.COLOR_NORMAL_TEXT))
self.finish_line()
i += 1
if contact.mood:
self.addstr(i, 0, 'Mood: %s' % contact.mood,
- to_curses_attr(get_theme().COLOR_NORMAL_TEXT))
+ to_curses_attr(theme.COLOR_NORMAL_TEXT))
self.finish_line()
i += 1
if contact.activity:
self.addstr(i, 0, 'Activity: %s' % contact.activity,
- to_curses_attr(get_theme().COLOR_NORMAL_TEXT))
+ to_curses_attr(theme.COLOR_NORMAL_TEXT))
self.finish_line()
i += 1
if contact.gaming:
self.addstr(
i, 0, 'Game: %s' % common.format_gaming_string(contact.gaming),
- to_curses_attr(get_theme().COLOR_NORMAL_TEXT))
+ to_curses_attr(theme.COLOR_NORMAL_TEXT))
self.finish_line()
i += 1
@@ -416,9 +424,10 @@ class ContactInfoWin(Win):
"""
draw the group information
"""
+ theme = get_theme()
self.addstr(0, 0, group.name,
- to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
- self.finish_line(get_theme().COLOR_INFORMATION_BAR)
+ to_curses_attr(theme.COLOR_INFORMATION_BAR))
+ self.finish_line(theme.COLOR_INFORMATION_BAR)
def refresh(self, selected_row: Row) -> None:
log.debug('Refresh: %s', self.__class__.__name__)
diff --git a/poezio/windows/text_win.py b/poezio/windows/text_win.py
index 76c7d2d7..1de905ea 100644
--- a/poezio/windows/text_win.py
+++ b/poezio/windows/text_win.py
@@ -32,6 +32,9 @@ class Line:
class BaseTextWin(Win):
+ __slots__ = ('lines_nb_limit', 'pos', 'built_lines', 'lock', 'lock_buffer',
+ 'separator_after')
+
def __init__(self, lines_nb_limit: Optional[int] = None) -> None:
if lines_nb_limit is None:
lines_nb_limit = config.get('max_lines_in_memory')
@@ -175,6 +178,8 @@ class BaseTextWin(Win):
class TextWin(BaseTextWin):
+ __slots__ = ('highlights', 'hl_pos', 'nb_of_highlights_after_separator')
+
def __init__(self, lines_nb_limit: Optional[int] = None) -> None:
BaseTextWin.__init__(self, lines_nb_limit)
@@ -190,8 +195,6 @@ class TextWin(BaseTextWin):
# This is useful to make “go to next highlight“ work after a “move to separator”.
self.nb_of_highlights_after_separator = 0
- self.separator_after = None
-
def next_highlight(self) -> None:
"""
Go to the next highlight in the buffer.
@@ -347,9 +350,10 @@ class TextWin(BaseTextWin):
txt = message.txt
if not txt:
return []
+ theme = get_theme()
if len(message.str_time) > 8:
default_color = (
- FORMAT_CHAR + dump_tuple(get_theme().COLOR_LOG_MSG) + '}') # type: Optional[str]
+ FORMAT_CHAR + dump_tuple(theme.COLOR_LOG_MSG) + '}') # type: Optional[str]
else:
default_color = None
ret = [] # type: List[Union[None, Line]]
@@ -357,9 +361,9 @@ class TextWin(BaseTextWin):
offset = 0
if message.ack:
if message.ack > 0:
- offset += poopt.wcswidth(get_theme().CHAR_ACK_RECEIVED) + 1
+ offset += poopt.wcswidth(theme.CHAR_ACK_RECEIVED) + 1
else:
- offset += poopt.wcswidth(get_theme().CHAR_NACK) + 1
+ offset += poopt.wcswidth(theme.CHAR_NACK) + 1
if nick:
offset += poopt.wcswidth(nick) + 2 # + nick + '> ' length
if message.revisions > 0:
@@ -369,9 +373,9 @@ class TextWin(BaseTextWin):
if timestamp:
if message.str_time:
offset += 1 + len(message.str_time)
- if get_theme().CHAR_TIME_LEFT and message.str_time:
+ if theme.CHAR_TIME_LEFT and message.str_time:
offset += 1
- if get_theme().CHAR_TIME_RIGHT and message.str_time:
+ if theme.CHAR_TIME_RIGHT and message.str_time:
offset += 1
lines = poopt.cut_text(txt, self.width - offset - 1)
prepend = default_color if default_color else ''
@@ -436,10 +440,11 @@ class TextWin(BaseTextWin):
nick = truncate_nick(msg.nickname, nick_size)
offset += poopt.wcswidth(nick)
if msg.ack:
+ theme = get_theme()
if msg.ack > 0:
- offset += poopt.wcswidth(get_theme().CHAR_ACK_RECEIVED) + 1
+ offset += poopt.wcswidth(theme.CHAR_ACK_RECEIVED) + 1
else:
- offset += poopt.wcswidth(get_theme().CHAR_NACK) + 1
+ offset += poopt.wcswidth(theme.CHAR_NACK) + 1
if msg.me:
offset += 3
else:
@@ -494,25 +499,28 @@ class TextWin(BaseTextWin):
return 0
def write_line_separator(self, y) -> None:
- char = get_theme().CHAR_NEW_TEXT_SEPARATOR
+ theme = get_theme()
+ char = theme.CHAR_NEW_TEXT_SEPARATOR
self.addnstr(y, 0, char * (self.width // len(char) - 1), self.width,
- to_curses_attr(get_theme().COLOR_NEW_TEXT_SEPARATOR))
+ to_curses_attr(theme.COLOR_NEW_TEXT_SEPARATOR))
def write_ack(self) -> int:
- color = get_theme().COLOR_CHAR_ACK
+ theme = get_theme()
+ color = theme.COLOR_CHAR_ACK
self._win.attron(to_curses_attr(color))
- self.addstr(get_theme().CHAR_ACK_RECEIVED)
+ self.addstr(theme.CHAR_ACK_RECEIVED)
self._win.attroff(to_curses_attr(color))
self.addstr(' ')
- return poopt.wcswidth(get_theme().CHAR_ACK_RECEIVED) + 1
+ return poopt.wcswidth(theme.CHAR_ACK_RECEIVED) + 1
def write_nack(self) -> int:
- color = get_theme().COLOR_CHAR_NACK
+ theme = get_theme()
+ color = theme.COLOR_CHAR_NACK
self._win.attron(to_curses_attr(color))
- self.addstr(get_theme().CHAR_NACK)
+ self.addstr(theme.CHAR_NACK)
self._win.attroff(to_curses_attr(color))
self.addstr(' ')
- return poopt.wcswidth(get_theme().CHAR_NACK) + 1
+ return poopt.wcswidth(theme.CHAR_NACK) + 1
def write_nickname(self, nickname, color, highlight=False) -> None:
"""
@@ -563,6 +571,8 @@ class TextWin(BaseTextWin):
class XMLTextWin(BaseTextWin):
+ __slots__ = ()
+
def __init__(self) -> None:
BaseTextWin.__init__(self)
@@ -621,9 +631,10 @@ class XMLTextWin(BaseTextWin):
offset += poopt.wcswidth(nick) + 1 # + nick + ' ' length
if message.str_time:
offset += 1 + len(message.str_time)
- if get_theme().CHAR_TIME_LEFT and message.str_time:
+ theme = get_theme()
+ if theme.CHAR_TIME_LEFT and message.str_time:
offset += 1
- if get_theme().CHAR_TIME_RIGHT and message.str_time:
+ if theme.CHAR_TIME_RIGHT and message.str_time:
offset += 1
lines = poopt.cut_text(txt, self.width - offset - 1)
prepend = default_color if default_color else ''