diff options
Diffstat (limited to 'src/windows/base_wins.py')
-rw-r--r-- | src/windows/base_wins.py | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/windows/base_wins.py b/src/windows/base_wins.py new file mode 100644 index 00000000..44c62e91 --- /dev/null +++ b/src/windows/base_wins.py @@ -0,0 +1,168 @@ +""" +Define the base window object and the constants/"globals" used +by the file of this module. + +A window is a little part of the screen, for example the input window, +the text window, the roster window, etc. +A Tab (see the src/tabs module) is composed of multiple Windows +""" + +import logging +log = logging.getLogger(__name__) + +import collections +import curses +import string +from threading import RLock + +import core +import singleton +from theming import to_curses_attr, read_tuple + +FORMAT_CHAR = '\x19' +# These are non-printable chars, so they should never appear in the input, +# I guess. But maybe we can find better chars that are even less risky. +format_chars = ['\x0E', '\x0F', '\x10', '\x11', '\x12', '\x13', + '\x14', '\x15', '\x16', '\x17', '\x18'] + +# different colors allowed in the input +allowed_color_digits = ('0', '1', '2', '3', '4', '5', '6', '7') + +# msg is a reference to the corresponding Message tuple. text_start and +# text_end are the position delimiting the text in this line. +Line = collections.namedtuple('Line', 'msg start_pos end_pos prepend') + +g_lock = RLock() + +LINES_NB_LIMIT = 4096 + +class DummyWin(object): + def __getattribute__(self, name): + if name != '__bool__': + return lambda *args, **kwargs: (0, 0) + else: + return object.__getattribute__(self, name) + + def __bool__(self): + return False + +class Win(object): + _win_core = None + _tab_win = None + def __init__(self): + self._win = None + self.height, self.width = 0, 0 + + def _resize(self, height, width, y, x): + if height == 0 or width == 0: + self.height, self.width = height, width + return + self.height, self.width, self.x, self.y = height, width, x, y + try: + self._win = Win._tab_win.derwin(height, width, y, x) + except: + log.debug('DEBUG: mvwin returned ERR. Please investigate') + if self._win is None: + self._win = DummyWin() + + def resize(self, height, width, y, x): + """ + Override if something has to be done on resize + """ + with g_lock: + self._resize(height, width, y, x) + + def _refresh(self): + self._win.noutrefresh() + + def addnstr(self, *args): + """ + Safe call to addnstr + """ + try: + self._win.addnstr(*args) + except: + # this actually mostly returns ERR, but works. + # more specifically, when the added string reaches the end + # of the screen. + pass + + def addstr(self, *args): + """ + Safe call to addstr + """ + try: + self._win.addstr(*args) + except: + pass + + def move(self, y, x): + try: + self._win.move(y, x) + except: + self._win.move(0, 0) + + def addstr_colored(self, text, y=None, x=None): + """ + Write a string on the window, setting the + attributes as they are in the string. + For example: + \x19bhello → hello in bold + \x191}Bonj\x192}our → 'Bonj' in red and 'our' in green + next_attr_char is the \x19 delimiter + attr_char is the char following it, it can be + one of 'u', 'b', 'c[0-9]' + """ + if y is not None and x is not None: + self.move(y, x) + next_attr_char = text.find(FORMAT_CHAR) + while next_attr_char != -1 and text: + if next_attr_char + 1 < len(text): + attr_char = text[next_attr_char+1].lower() + else: + attr_char = str() + if next_attr_char != 0: + self.addstr(text[:next_attr_char]) + if attr_char == 'o': + self._win.attrset(0) + elif attr_char == 'u': + self._win.attron(curses.A_UNDERLINE) + elif attr_char == 'b': + self._win.attron(curses.A_BOLD) + if (attr_char in string.digits or attr_char == '-') and attr_char != '': + color_str = text[next_attr_char+1:text.find('}', next_attr_char)] + if ',' in color_str: + tup, char = read_tuple(color_str) + self._win.attron(to_curses_attr(tup)) + if char: + if char == 'o': + self._win.attrset(0) + elif char == 'u': + self._win.attron(curses.A_UNDERLINE) + elif char == 'b': + self._win.attron(curses.A_BOLD) + elif color_str: + self._win.attron(to_curses_attr((int(color_str), -1))) + text = text[next_attr_char+len(color_str)+2:] + else: + text = text[next_attr_char+2:] + next_attr_char = text.find(FORMAT_CHAR) + self.addstr(text) + + def finish_line(self, color=None): + """ + Write colored spaces until the end of line + """ + (y, x) = self._win.getyx() + size = self.width - x + if color: + self.addnstr(' '*size, size, to_curses_attr(color)) + else: + self.addnstr(' '*size, size) + + @property + def core(self): + if not Win._win_core: + Win._win_core = singleton.Singleton(core.Core) + return Win._win_core + |