summaryrefslogtreecommitdiff
path: root/src/windows/base_wins.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/base_wins.py')
-rw-r--r--src/windows/base_wins.py168
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
+