summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2011-09-21 00:52:03 +0200
committerFlorent Le Coz <louiz@louiz.org>2011-09-21 00:52:03 +0200
commit700b11e42d8045e8f4ef53588aab8e44dd9ac010 (patch)
treee913e8d5cd50701d6c95f4db6a11bb477744dbb3
parent46705e18611cf49e5c0b45ce51ced221b0162167 (diff)
downloadpoezio-700b11e42d8045e8f4ef53588aab8e44dd9ac010.tar.gz
poezio-700b11e42d8045e8f4ef53588aab8e44dd9ac010.tar.bz2
poezio-700b11e42d8045e8f4ef53588aab8e44dd9ac010.tar.xz
poezio-700b11e42d8045e8f4ef53588aab8e44dd9ac010.zip
Handles 256 colors, easier theming and more flexible way to define colors
Doesn’t run yet if term doesn’t support 256 colors, I know (thus the branch "256")
-rw-r--r--src/common.py5
-rw-r--r--src/core.py22
-rw-r--r--src/room.py24
-rw-r--r--src/tabs.py144
-rw-r--r--src/text_buffer.py1
-rw-r--r--src/theme.py173
-rw-r--r--src/theming.py232
-rw-r--r--src/user.py8
-rw-r--r--src/windows.py203
9 files changed, 421 insertions, 391 deletions
diff --git a/src/common.py b/src/common.py
index db750b30..11a09b93 100644
--- a/src/common.py
+++ b/src/common.py
@@ -186,11 +186,6 @@ def shell_split(st):
except ValueError:
return st.split(" ")
-def curses_color_pair(color):
- if color < 0:
- return curses.color_pair(-color) | curses.A_BOLD
- return curses.color_pair(color)
-
def replace_key_with_bound(key):
if config.has_option('bindings', key):
return config.get(key, key, 'bindings')
diff --git a/src/core.py b/src/core.py
index 96531e5f..c47af752 100644
--- a/src/core.py
+++ b/src/core.py
@@ -18,7 +18,7 @@ import traceback
from datetime import datetime
import common
-import theme
+import theming
import logging
import singleton
import collections
@@ -45,6 +45,7 @@ from roster import Roster, RosterGroup, roster
from contact import Contact, Resource
from text_buffer import TextBuffer
from keyboard import read_char
+from theming import get_theme
# http://xmpp.org/extensions/xep-0045.html#errorstatus
ERROR_AND_STATUS_CODES = {
@@ -603,7 +604,7 @@ class Core(object):
remote_nick = roster.get_contact_by_jid(jid.bare).get_name() or jid.user
else:
remote_nick = jid.user
- conversation.get_room().add_message(body, nickname=remote_nick, nick_color=theme.COLOR_REMOTE_USER)
+ conversation.get_room().add_message(body, nickname=remote_nick, nick_color=get_theme().COLOR_REMOTE_USER)
if conversation.remote_wants_chatstates is None:
if message['chat_state']:
conversation.remote_wants_chatstates = True
@@ -613,7 +614,7 @@ class Core(object):
if 'private' in config.get('beep_on', 'highlight private').split():
curses.beep()
if self.current_tab() is not conversation:
- conversation.set_color_state(theme.COLOR_TAB_PRIVATE)
+ conversation.set_color_state(get_theme().COLOR_TAB_PRIVATE)
self.refresh_tab_win()
else:
self.refresh_window()
@@ -675,7 +676,7 @@ class Core(object):
roster.add_contact(contact, jid)
roster.edit_groups_of_contact(contact, [])
contact.set_ask('asked')
- self.get_tab_by_number(0).set_color_state(theme.COLOR_TAB_HIGHLIGHT)
+ self.get_tab_by_number(0).set_color_state(get_theme().COLOR_TAB_HIGHLIGHT)
self.information('%s wants to subscribe to your presence'%jid, 'Roster')
if isinstance(self.current_tab(), tabs.RosterInfoTab):
self.refresh_window()
@@ -804,9 +805,10 @@ class Core(object):
curses.noecho()
curses.nonl()
curses.raw()
- theme.init_colors()
stdscr.idlok(True)
stdscr.keypad(True)
+ curses.start_color()
+ curses.use_default_colors()
curses.ungetch(" ") # H4X: without this, the screen is
stdscr.getkey() # erased on the first "getkey()"
@@ -824,7 +826,7 @@ class Core(object):
"""
Refresh everything
"""
- self.current_tab().set_color_state(theme.COLOR_TAB_CURRENT)
+ self.current_tab().set_color_state(get_theme().COLOR_TAB_CURRENT)
self.current_tab().refresh()
self.doupdate()
@@ -872,15 +874,15 @@ class Core(object):
- A Muc with any new message
"""
for tab in self.tabs:
- if tab.get_color_state() == theme.COLOR_TAB_PRIVATE:
+ if tab.get_color_state() == get_theme().COLOR_TAB_PRIVATE:
self.command_win('%s' % tab.nb)
return
for tab in self.tabs:
- if tab.get_color_state() == theme.COLOR_TAB_HIGHLIGHT:
+ if tab.get_color_state() == get_theme().COLOR_TAB_HIGHLIGHT:
self.command_win('%s' % tab.nb)
return
for tab in self.tabs:
- if tab.get_color_state() == theme.COLOR_TAB_NEW_MESSAGE:
+ if tab.get_color_state() == get_theme().COLOR_TAB_NEW_MESSAGE:
self.command_win('%s' % tab.nb)
return
for tab in self.tabs:
@@ -1179,7 +1181,7 @@ class Core(object):
def command_theme(self, arg):
"""
"""
- theme.reload_theme()
+ # get_theme().reload_theme()
self.refresh_window()
def command_win(self, arg):
diff --git a/src/room.py b/src/room.py
index 83b00e62..37b0de66 100644
--- a/src/room.py
+++ b/src/room.py
@@ -12,7 +12,7 @@ from config import config
from logger import logger
import common
-import theme
+from theming import get_theme
import logging
import curses
@@ -24,7 +24,7 @@ class Room(TextBuffer):
TextBuffer.__init__(self, messages_nb_limit)
self.name = name
self.own_nick = nick
- self.color_state = theme.COLOR_TAB_NORMAL # color used in RoomInfo
+ self.color_state = get_theme().COLOR_TAB_NORMAL # color used in RoomInfo
self.joined = False # false until self presence is receied
self.users = [] # User objects
self.topic = ''
@@ -35,7 +35,7 @@ class Room(TextBuffer):
we can know if we can join it, send messages to it, etc
"""
self.users = []
- self.color_state = theme.COLOR_TAB_DISCONNECTED
+ self.color_state = get_theme().COLOR_TAB_DISCONNECTED
self.joined = False
def get_single_line_topic(self):
@@ -59,16 +59,16 @@ class Room(TextBuffer):
color = None
if not time and nickname and nickname != self.own_nick and self.joined:
if self.own_nick.lower() in txt.lower():
- if self.color_state != theme.COLOR_TAB_CURRENT:
- self.set_color_state(theme.COLOR_TAB_HIGHLIGHT)
- color = theme.COLOR_HIGHLIGHT_NICK
+ if self.color_state != get_theme().COLOR_TAB_CURRENT:
+ self.set_color_state(get_theme().COLOR_TAB_HIGHLIGHT)
+ color = get_theme().COLOR_HIGHLIGHT_NICK
else:
highlight_words = config.get('highlight_on', '').split(':')
for word in highlight_words:
if word and word.lower() in txt.lower():
- if self.color_state != theme.COLOR_TAB_CURRENT:
- self.set_color_state(theme.COLOR_TAB_HIGHLIGHT)
- color = theme.COLOR_HIGHLIGHT_NICK
+ if self.color_state != get_theme().COLOR_TAB_CURRENT:
+ self.set_color_state(get_theme().COLOR_TAB_HIGHLIGHT)
+ color = get_theme().COLOR_HIGHLIGHT_NICK
break
if color:
beep_on = config.get('beep_on', 'highlight private').split()
@@ -110,9 +110,9 @@ class Room(TextBuffer):
user = forced_user
if not time and nickname and\
nickname != self.own_nick and\
- self.color_state != theme.COLOR_TAB_CURRENT:
- if self.color_state != theme.COLOR_TAB_HIGHLIGHT:
- self.set_color_state(theme.COLOR_TAB_NEW_MESSAGE)
+ self.color_state != get_theme().COLOR_TAB_CURRENT:
+ if self.color_state != get_theme().COLOR_TAB_HIGHLIGHT:
+ self.set_color_state(get_theme().COLOR_TAB_NEW_MESSAGE)
nick_color = nick_color or None
if not nickname or time:
txt = '\x195%s' % (txt,)
diff --git a/src/tabs.py b/src/tabs.py
index 5c141f51..ea08d6f5 100644
--- a/src/tabs.py
+++ b/src/tabs.py
@@ -13,13 +13,15 @@ Each Tab object has different refresh() and resize() methods, defining how its
Windows are displayed, resized, etc
"""
+MIN_WIDTH = 50
+MIN_HEIGHT = 22
+
import logging
log = logging.getLogger(__name__)
from gettext import gettext as _
import windows
-import theme
import curses
import difflib
import text_buffer
@@ -33,6 +35,8 @@ import timed_events
import multiuserchat as muc
+from theming import get_theme
+
from sleekxmpp.xmlstream.stanzabase import JID
from config import config
from roster import RosterGroup, roster
@@ -58,7 +62,7 @@ class Tab(object):
tab_core = None
def __init__(self):
self.input = None
- self._color_state = theme.COLOR_TAB_NORMAL
+ self._color_state = get_theme().COLOR_TAB_NORMAL
self.need_resize = False
self.nb = Tab.number
Tab.number += 1
@@ -86,7 +90,10 @@ class Tab(object):
@staticmethod
def resize(scr):
Tab.size = (Tab.height, Tab.width) = scr.getmaxyx()
- Tab.visible = True
+ if Tab.height < MIN_HEIGHT or Tab.width < MIN_WIDTH:
+ Tab.visible = False
+ else:
+ Tab.visible = True
def complete_commands(self, the_input):
"""
@@ -185,13 +192,13 @@ class Tab(object):
"""
called when this tab loses the focus.
"""
- self._color_state = theme.COLOR_TAB_NORMAL
+ self._color_state = get_theme().COLOR_TAB_NORMAL
def on_gain_focus(self):
"""
called when this tab gains the focus.
"""
- self._color_state = theme.COLOR_TAB_CURRENT
+ self._color_state = get_theme().COLOR_TAB_CURRENT
def add_message(self):
"""
@@ -467,9 +474,9 @@ class MucTab(ChatTab):
for user in users:
if user.nick == room.own_nick:
users.remove(user)
- nb_color = len(theme.LIST_COLOR_NICKNAMES)
+ nb_color = len(get_theme().LIST_COLOR_NICKNAMES)
for i, user in enumerate(sorted(users, key=compare_users, reverse=True)):
- user.color = theme.LIST_COLOR_NICKNAMES[i % nb_color]
+ user.color = get_theme().LIST_COLOR_NICKNAMES[i % nb_color]
self.text_win.rebuild_everything(self._room)
self.text_win.refresh(self._room)
self.input.refresh()
@@ -674,7 +681,6 @@ class MucTab(ChatTab):
"""
if not self.visible:
return
- self.need_resize = False
text_width = (self.width//10)*9
self.topic_win.resize(1, self.width, 0, 0)
self.v_separator.resize(self.height-3, 1, 1, 9*(self.width//10))
@@ -744,14 +750,14 @@ class MucTab(ChatTab):
return self._room
def on_lose_focus(self):
- self._room.set_color_state(theme.COLOR_TAB_NORMAL)
+ self._room.set_color_state(get_theme().COLOR_TAB_NORMAL)
self.text_win.remove_line_separator()
self.text_win.add_line_separator()
if config.get('send_chat_states', 'true') == 'true' and not self.input.get_text():
self.send_chat_state('inactive')
def on_gain_focus(self):
- self._room.set_color_state(theme.COLOR_TAB_CURRENT)
+ self._room.set_color_state(get_theme().COLOR_TAB_CURRENT)
if self.text_win.built_lines and self.text_win.built_lines[-1] is None:
self.text_win.remove_line_separator()
curses.curs_set(1)
@@ -794,7 +800,7 @@ class MucTab(ChatTab):
if from_nick == room.own_nick:
room.joined = True
self.send_chat_state('active')
- new_user.color = theme.COLOR_OWN_NICK
+ new_user.color = get_theme().COLOR_OWN_NICK
room.add_message(_("\x195Your nickname is \x193%s") % (from_nick))
if '170' in status_codes:
room.add_message('\x191Warning: \x195this room is publicly logged')
@@ -836,9 +842,9 @@ class MucTab(ChatTab):
hide_exit_join = config.get('hide_exit_join', -1)
if hide_exit_join != 0:
if not jid.full:
- room.add_message('\x194%(spec)s \x193%(nick)s\x195 joined the room' % {'nick':from_nick, 'spec':theme.CHAR_JOIN})
+ room.add_message('\x194%(spec)s \x193%(nick)s\x195 joined the room' % {'nick':from_nick, 'spec':get_theme().CHAR_JOIN})
else:
- room.add_message('\x194%(spec)s \x193%(nick)s \x195(\x194%(jid)s\x195) joined the room' % {'spec':theme.CHAR_JOIN, 'nick':from_nick, 'jid':jid.full})
+ room.add_message('\x194%(spec)s \x193%(nick)s \x195(\x194%(jid)s\x195) joined the room' % {'spec':get_theme().CHAR_JOIN, 'nick':from_nick, 'jid':jid.full})
self.core.on_user_rejoined_private_conversation(room.name, from_nick)
@@ -869,14 +875,14 @@ class MucTab(ChatTab):
self.tab_win.refresh()
self.core.doupdate()
if by:
- kick_msg = _('\x191%(spec)s \x193You\x195 have been banned by \x194%(by)s') % {'spec': theme.CHAR_KICK, 'by':by}
+ kick_msg = _('\x191%(spec)s \x193You\x195 have been banned by \x194%(by)s') % {'spec': get_theme().CHAR_KICK, 'by':by}
else:
- kick_msg = _('\x191%(spec)s \x193You\x195 have been banned.') % {'spec':theme.CHAR_KICK}
+ kick_msg = _('\x191%(spec)s \x193You\x195 have been banned.') % {'spec':get_theme().CHAR_KICK}
else:
if by:
- kick_msg = _('\x191%(spec)s \x193%(nick)s\x195 has been banned by \x194%(by)s') % {'spec':theme.CHAR_KICK, 'nick':from_nick, 'by':by}
+ kick_msg = _('\x191%(spec)s \x193%(nick)s\x195 has been banned by \x194%(by)s') % {'spec':get_theme().CHAR_KICK, 'nick':from_nick, 'by':by}
else:
- kick_msg = _('\x191%(spec)s \x193%(nick)s\x195 has been banned') % {'spec':theme.CHAR_KICK, 'nick':from_nick.replace('"', '\\"')}
+ kick_msg = _('\x191%(spec)s \x193%(nick)s\x195 has been banned') % {'spec':get_theme().CHAR_KICK, 'nick':from_nick.replace('"', '\\"')}
if reason is not None and reason.text:
kick_msg += _('\x195 Reason: \x196%(reason)s\x195') % {'reason': reason.text}
room.add_message(kick_msg)
@@ -895,17 +901,17 @@ class MucTab(ChatTab):
self.tab_win.refresh()
self.core.doupdate()
if by:
- kick_msg = _('\x191%(spec)s \x193You\x195 have been kicked by \x193%(by)s') % {'spec': theme.CHAR_KICK, 'by':by}
+ kick_msg = _('\x191%(spec)s \x193You\x195 have been kicked by \x193%(by)s') % {'spec': get_theme().CHAR_KICK, 'by':by}
else:
- kick_msg = _('\x191%(spec)s \x193You\x195 have been kicked.') % {'spec':theme.CHAR_KICK}
+ kick_msg = _('\x191%(spec)s \x193You\x195 have been kicked.') % {'spec':get_theme().CHAR_KICK}
# try to auto-rejoin
if config.get('autorejoin', 'false') == 'true':
muc.join_groupchat(self.core.xmpp, room.name, room.own_nick)
else:
if by:
- kick_msg = _('\x191%(spec)s \x193%(nick)s\x195 has been kicked by \x193%(by)s') % {'spec':theme.CHAR_KICK.replace('"', '\\"'), 'nick':from_nick.replace('"', '\\"'), 'by':by.replace('"', '\\"')}
+ kick_msg = _('\x191%(spec)s \x193%(nick)s\x195 has been kicked by \x193%(by)s') % {'spec':get_theme().CHAR_KICK.replace('"', '\\"'), 'nick':from_nick.replace('"', '\\"'), 'by':by.replace('"', '\\"')}
else:
- kick_msg = _('\x191%(spec)s \x193%(nick)s\x195 has been kicked') % {'spec':theme.CHAR_KICK, 'nick':from_nick.replace('"', '\\"')}
+ kick_msg = _('\x191%(spec)s \x193%(nick)s\x195 has been kicked') % {'spec':get_theme().CHAR_KICK, 'nick':from_nick.replace('"', '\\"')}
if reason is not None and reason.text:
kick_msg += _('\x195 Reason: \x196%(reason)s') % {'reason': reason.text}
room.add_message(kick_msg)
@@ -924,9 +930,9 @@ class MucTab(ChatTab):
hide_exit_join = config.get('hide_exit_join', -1) if config.get('hide_exit_join', -1) >= -1 else -1
if hide_exit_join == -1 or user.has_talked_since(hide_exit_join):
if not jid.full:
- leave_msg = _('\x191%(spec)s \x193%(nick)s\x195 has left the room') % {'nick':from_nick, 'spec':theme.CHAR_QUIT}
+ leave_msg = _('\x191%(spec)s \x193%(nick)s\x195 has left the room') % {'nick':from_nick, 'spec':get_theme().CHAR_QUIT}
else:
- leave_msg = _('\x191%(spec)s \x193%(nick)s\x195 (\x194%(jid)s\x195) has left the room') % {'spec':theme.CHAR_QUIT, 'nick':from_nick, 'jid':jid.full}
+ leave_msg = _('\x191%(spec)s \x193%(nick)s\x195 (\x194%(jid)s\x195) has left the room') % {'spec':get_theme().CHAR_QUIT, 'nick':from_nick, 'jid':jid.full}
if status:
leave_msg += ' (%s)' % status
room.add_message(leave_msg)
@@ -993,12 +999,10 @@ class PrivateTab(ChatTab):
# keys
self.key_func['^I'] = self.completion
# commands
- self.commands['info'] = (self.command_info, _('Usage: /info\nInfo: Display some information about the user in the MUC: '), None)
+ #self.commands['info'] = (self.command_info, _('Usage: /info\nInfo: Display some information about the user in the MUC: '), None)
self.commands['unquery'] = (self.command_unquery, _("Usage: /unquery\nUnquery: close the tab"), None)
self.commands['part'] = (self.command_unquery, _("Usage: /part\nPart: close the tab"), None)
- self.commands['version'] = (self.command_version, _('Usage: /version\nVersion: get the software version of the current interlocutor (usually its XMPP client and Operating System)'), None)
self.resize()
- self.parent_muc = self.core.get_tab_by_name(JID(room.name).bare, MucTab)
self.on = True
def completion(self):
@@ -1029,35 +1033,9 @@ class PrivateTab(ChatTab):
"""
self.core.close_tab()
- def command_version(self, arg):
- """
- /version
- """
- def callback(res):
- if not res:
- return self.core.information('Could not get the software version from %s' % (jid,), 'Warning')
- version = '%s is running %s version %s on %s' % (jid,
- res.get('name') or _('an unknown software'),
- res.get('version') or _('unknown'),
- res.get('os') or _('on an unknown platform'))
- self.core.information(version, 'Info')
- jid = self.get_room().name
- self.core.xmpp.plugin['xep_0092'].get_version(jid, callback=callback)
-
- def command_info(self, arg):
- """
- /info
- """
- if arg:
- self.parent_muc.command_info(arg)
- else:
- user = JID(self.get_room().name).resource
- self.parent_muc.command_info(user)
-
def resize(self):
if self.core.information_win_size >= self.height-3 or not self.visible:
return
- self.need_resize = False
self.text_win.resize(self.height-3-self.core.information_win_size, self.width, 0, 0)
self.text_win.rebuild_everything(self._room)
self.info_header.resize(1, self.width, self.height-3-self.core.information_win_size, 0)
@@ -1078,10 +1056,10 @@ class PrivateTab(ChatTab):
self.input.refresh()
def get_color_state(self):
- if self._room.color_state == theme.COLOR_TAB_NORMAL or\
- self._room.color_state == theme.COLOR_TAB_CURRENT:
+ if self._room.color_state == get_theme().COLOR_TAB_NORMAL or\
+ self._room.color_state == get_theme().COLOR_TAB_CURRENT:
return self._room.color_state
- return theme.COLOR_TAB_PRIVATE
+ return get_theme().COLOR_TAB_PRIVATE
def set_color_state(self, color):
self._room.color_state = color
@@ -1103,14 +1081,14 @@ class PrivateTab(ChatTab):
return False
def on_lose_focus(self):
- self._room.set_color_state(theme.COLOR_TAB_NORMAL)
+ self._room.set_color_state(get_theme().COLOR_TAB_NORMAL)
self.text_win.remove_line_separator()
self.text_win.add_line_separator()
if self.get_room().joined and config.get('send_chat_states', 'true') == 'true' and not self.input.get_text():
self.send_chat_state('inactive')
def on_gain_focus(self):
- self._room.set_color_state(theme.COLOR_TAB_CURRENT)
+ self._room.set_color_state(get_theme().COLOR_TAB_CURRENT)
curses.curs_set(1)
if self.get_room().joined and config.get('send_chat_states', 'true') == 'true' and not self.input.get_text():
self.send_chat_state('active')
@@ -1146,24 +1124,22 @@ class PrivateTab(ChatTab):
"""
The user left the associated MUC
"""
- self.deactivate()
if not status_message:
- self.get_room().add_message(_('\x191%(spec)s \x193%(nick)s\x195 has left the room') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_QUIT.replace('"', '\\"')})
+ self.get_room().add_message(_('\x191%(spec)s \x193%(nick)s\x195 has left the room') % {'nick':from_nick.replace('"', '\\"'), 'spec':get_theme().CHAR_QUIT.replace('"', '\\"')})
else:
- self.get_room().add_message(_('\x191%(spec)s \x193%(nick)s\x195 has left the room (%(status)s)"') % {'nick':from_nick.replace('"', '\\"'), 'spec':theme.CHAR_QUIT, 'status': status_message.replace('"', '\\"')})
- if self.core.current_tab() is self:
- self.refresh()
- self.core.doupdate()
+ self.get_room().add_message(_('\x191%(spec)s \x193%(nick)s\x195 has left the room (%(status)s)"') % {'nick':from_nick.replace('"', '\\"'), 'spec':get_theme().CHAR_QUIT, 'status': status_message.replace('"', '\\"')})
+ self.deactivate()
+ self.refresh()
+ self.core.doupdate()
def user_rejoined(self, nick):
"""
The user (or at least someone with the same nick) came back in the MUC
"""
+ self.get_room().add_message('\x194%(spec)s \x193%(nick)s\x195 joined the room' % {'nick':nick, 'spec':get_theme().CHAR_JOIN})
self.activate()
- self.get_room().add_message('\x194%(spec)s \x193%(nick)s\x195 joined the room' % {'nick':nick, 'spec':theme.CHAR_JOIN})
- if self.core.current_tab() is self:
- self.refresh()
- self.core.doupdate()
+ self.refresh()
+ self.core.doupdate()
def activate(self):
self.on = True
@@ -1185,7 +1161,7 @@ class RosterInfoTab(Tab):
self.contact_info_win = windows.ContactInfoWin()
self.default_help_message = windows.HelpText("Enter commands with “/”. “o”: toggle offline show")
self.input = self.default_help_message
- self.set_color_state(theme.COLOR_TAB_NORMAL)
+ self.set_color_state(get_theme().COLOR_TAB_NORMAL)
self.key_func['^I'] = self.completion
self.key_func[' '] = self.on_space
self.key_func["/"] = self.on_slash
@@ -1209,7 +1185,6 @@ class RosterInfoTab(Tab):
def resize(self):
if not self.visible:
return
- self.need_resize = False
roster_width = self.width//2
info_width = self.width-roster_width-1
self.v_separator.resize(self.height-2, 1, 0, roster_width)
@@ -1420,10 +1395,10 @@ class RosterInfoTab(Tab):
return self.reset_help_message()
def on_lose_focus(self):
- self._color_state = theme.COLOR_TAB_NORMAL
+ self._color_state = get_theme().COLOR_TAB_NORMAL
def on_gain_focus(self):
- self._color_state = theme.COLOR_TAB_CURRENT
+ self._color_state = get_theme().COLOR_TAB_CURRENT
if isinstance(self.input, windows.HelpText):
curses.curs_set(0)
else:
@@ -1526,7 +1501,7 @@ class ConversationTab(ChatTab):
def __init__(self, jid):
txt_buff = text_buffer.TextBuffer()
ChatTab.__init__(self, txt_buff)
- self.color_state = theme.COLOR_TAB_NORMAL
+ self.color_state = get_theme().COLOR_TAB_NORMAL
self._name = jid # a conversation tab is linked to one specific full jid OR bare jid
self.text_win = windows.TextWin()
txt_buff.add_window(self.text_win)
@@ -1566,7 +1541,6 @@ class ConversationTab(ChatTab):
def resize(self):
if self.core.information_win_size >= self.height-3 or not self.visible:
return
- self.need_resize = False
self.text_win.resize(self.height-4-self.core.information_win_size, self.width, 1, 0)
self.text_win.rebuild_everything(self._room)
self.upper_bar.resize(1, self.width, 0, 0)
@@ -1589,10 +1563,10 @@ class ConversationTab(ChatTab):
self.input.refresh()
def get_color_state(self):
- if self.color_state == theme.COLOR_TAB_NORMAL or\
- self.color_state == theme.COLOR_TAB_CURRENT:
+ if self.color_state == get_theme().COLOR_TAB_NORMAL or\
+ self.color_state == get_theme().COLOR_TAB_CURRENT:
return self.color_state
- return theme.COLOR_TAB_PRIVATE
+ return get_theme().COLOR_TAB_PRIVATE
def set_color_state(self, color):
self.color_state = color
@@ -1610,14 +1584,14 @@ class ConversationTab(ChatTab):
return False
def on_lose_focus(self):
- self.set_color_state(theme.COLOR_TAB_NORMAL)
+ self.set_color_state(get_theme().COLOR_TAB_NORMAL)
self.text_win.remove_line_separator()
self.text_win.add_line_separator()
if config.get('send_chat_states', 'true') == 'true' and not self.input.get_text() or not self.input.get_text().startswith('//'):
self.send_chat_state('inactive')
def on_gain_focus(self):
- self.set_color_state(theme.COLOR_TAB_CURRENT)
+ self.set_color_state(get_theme().COLOR_TAB_CURRENT)
curses.curs_set(1)
if config.get('send_chat_states', 'true') == 'true' and not self.input.get_text() or not self.input.get_text().startswith('//'):
self.send_chat_state('active')
@@ -1652,7 +1626,7 @@ class MucListTab(Tab):
"""
def __init__(self, server):
Tab.__init__(self)
- self._color_state = theme.COLOR_TAB_NORMAL
+ self._color_state = get_theme().COLOR_TAB_NORMAL
self.name = server
self.upper_message = windows.Topic()
self.upper_message.set_message('Chatroom list on server %s (Loading)' % self.name)
@@ -1684,7 +1658,6 @@ class MucListTab(Tab):
def resize(self):
if not self.visible:
return
- self.need_resize = False
self.upper_message.resize(1, self.width, 0, 0)
column_size = {'node-part': (self.width-5)//4,
'name': (self.width-5)//4*3,
@@ -1766,10 +1739,10 @@ class MucListTab(Tab):
return self.key_func[key]()
def on_lose_focus(self):
- self._color_state = theme.COLOR_TAB_NORMAL
+ self._color_state = get_theme().COLOR_TAB_NORMAL
def on_gain_focus(self):
- self._color_state = theme.COLOR_TAB_CURRENT
+ self._color_state = get_theme().COLOR_TAB_CURRENT
curses.curs_set(0)
def get_color_state(self):
@@ -1789,7 +1762,7 @@ class SimpleTextTab(Tab):
"""
def __init__(self, text):
Tab.__init__(self)
- self._color_state = theme.COLOR_TAB_NORMAL
+ self._color_state = get_theme().COLOR_TAB_NORMAL
self.text_win = windows.SimpleTextWin(text)
self.default_help_message = windows.HelpText("“Ctrl+q”: close")
self.input = self.default_help_message
@@ -1819,7 +1792,6 @@ class SimpleTextTab(Tab):
def resize(self):
if not self.visible:
return
- self.need_resize = False
self.text_win.resize(self.height-2, self.width, 0, 0)
self.input.resize(1, self.width, self.height-1, 0)
@@ -1832,10 +1804,10 @@ class SimpleTextTab(Tab):
self.input.refresh()
def on_lose_focus(self):
- self._color_state = theme.COLOR_TAB_NORMAL
+ self._color_state = get_theme().COLOR_TAB_NORMAL
def on_gain_focus(self):
- self._color_state = theme.COLOR_TAB_CURRENT
+ self._color_state = get_theme().COLOR_TAB_CURRENT
curses.curs_set(0)
def get_color_state(self):
diff --git a/src/text_buffer.py b/src/text_buffer.py
index d89dbfb9..f39f147a 100644
--- a/src/text_buffer.py
+++ b/src/text_buffer.py
@@ -15,7 +15,6 @@ log = logging.getLogger(__name__)
import collections
from datetime import datetime
-import theme
from config import config
Message = collections.namedtuple('Message', 'txt nick_color time str_time nickname user')
diff --git a/src/theme.py b/src/theme.py
deleted file mode 100644
index 2502e5c6..00000000
--- a/src/theme.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# Copyright 2010-2011 Florent Le Coz <louiz@louiz.org>
-#
-# This file is part of Poezio.
-#
-# Poezio is free software: you can redistribute it and/or modify
-# it under the terms of the zlib license. See the COPYING file.
-
-"""
-Define the variables (colors and some other stuff) that are
-used when drawing the interface (mainly colors)
-"""
-
-import curses
-import glob
-import imp
-import os
-from config import config
-
-import logging
-log = logging.getLogger(__name__)
-
-## Define the default colors
-## Do not change these colors, create a theme file instead.
-
-# Message text color
-COLOR_NORMAL_TEXT = 0
-COLOR_INFORMATION_TEXT = 5
-COLOR_HIGHLIGHT_NICK = -46
-
-# User list color
-COLOR_USER_VISITOR = 7
-COLOR_USER_PARTICIPANT = 4
-COLOR_USER_NONE = 0
-COLOR_USER_MODERATOR = 1
-
-# nickname colors
-COLOR_REMOTE_USER = 5
-
-# The character printed in color (COLOR_STATUS_*) before the nickname
-# in the user list
-CHAR_STATUS = ' '
-
-# Separators
-COLOR_VERTICAL_SEPARATOR = 4
-COLOR_NEW_TEXT_SEPARATOR = 2
-COLOR_MORE_INDICATOR = 6
-
-# Time
-COLOR_TIME_SEPARATOR = 6
-COLOR_TIME_LIMITER = 0
-CHAR_TIME_LEFT = ''
-CHAR_TIME_RIGHT = ''
-COLOR_TIME_NUMBERS = 0
-
-# Tabs
-COLOR_TAB_NORMAL = 42
-COLOR_TAB_CURRENT = 56
-COLOR_TAB_NEW_MESSAGE = 49
-COLOR_TAB_HIGHLIGHT = 21
-COLOR_TAB_PRIVATE = 28
-COLOR_TAB_DISCONNECTED = 30
-
-# Nickname colors
-LIST_COLOR_NICKNAMES = [
- 1, 2, 3, 4, 5, 6, -2, -4, -5, -6
- ]
-COLOR_OWN_NICK = 7
-
-# Status color
-COLOR_STATUS_XA = 49
-COLOR_STATUS_NONE = 0
-COLOR_STATUS_DND = 21
-COLOR_STATUS_AWAY = 35
-COLOR_STATUS_CHAT = 28
-COLOR_STATUS_UNAVAILABLE = 57
-COLOR_STATUS_ONLINE = 41
-
-# Bars
-COLOR_INFORMATION_BAR = 42
-COLOR_TOPIC_BAR = 42
-COLOR_PRIVATE_ROOM_BAR = 28
-COLOR_SCROLLABLE_NUMBER = -39
-COLOR_SELECTED_ROW = 42
-COLOR_PRIVATE_NAME = 42
-COLOR_CONVERSATION_NAME = 42
-COLOR_GROUPCHAT_NAME = 42
-COLOR_COLUMN_HEADER = 36
-
-# Strings for special messages (like join, quit, nick change, etc)
-# Special messages
-CHAR_JOIN = '---->'
-CHAR_QUIT = '<----'
-CHAR_KICK = '-!-'
-
-COLOR_JOIN_CHAR = 4
-COLOR_QUIT_CHAR = 1
-COLOR_KICK_CHAR = 1
-
-# words between ()
-COLOR_CURLYBRACKETED_WORD = 4
-# words between {}
-COLOR_ACCOLADE_WORD = 6
-# words between []
-COLOR_BRACKETED_WORD = 3
-
-def init_colors():
- """
- Initilization of all the available ncurses colors
- limit the number of colors to 64 (because some terminals
- don't handle more than that), by removing some useless colors
- like 'black on black', etc.
- """
- curses.start_color()
- curses.use_default_colors()
- cpt = 0
- for i in range(-1, 7):
- for y in range(0, 8):
- if y == i:
- continue
- curses.init_pair(cpt, y, i)
- cpt += 1
- for y in range(0, 7):
- # init the default fg on others bg at last
- curses.init_pair(cpt, -1, y)
- cpt += 1
- # Have the default color be default fg on default bg
- reload_theme()
-
-def reload_theme():
- themes_dir = config.get('themes_dir', '')
- themes_dir = themes_dir or\
- os.path.join(os.environ.get('XDG_DATA_HOME') or\
- os.path.join(os.environ.get('HOME'), '.local', 'share'),
- 'poezio', 'themes')
- try:
- os.makedirs(themes_dir)
- except OSError:
- pass
- theme_name = config.get('theme', '')
- if not theme_name:
- return
- try:
- theme = imp.load_source('theme', os.path.join(themes_dir, theme_name))
- except: # TODO warning: theme not found
- return
- for var in dir(theme):
- if var.startswith('COLOR_') or var.startswith('CHAR_') or var.startswith('LIST_'):
- globals()[var] = getattr(theme, var)
-
-if __name__ == '__main__':
- """
- Launch 'python theme.py' to see the list of all the available colors
- in your terminal
- """
- s = curses.initscr()
- curses.start_color()
- curses.use_default_colors()
- init_colors()
- for i in range(64):
- s.attron(curses.color_pair(i) | curses.A_BOLD)
- s.addstr(str(curses.color_pair(i) | curses.A_BOLD))
- s.attroff(curses.color_pair(i) | curses.A_BOLD)
- s.addstr(' ')
- s.addstr('\n')
- for i in range(64):
- s.attron(curses.color_pair(i))
- s.addstr(str(i))
- s.attroff(curses.color_pair(i))
- s.addstr(' ')
-
- s.refresh()
- s.getch()
- s.endwin()
diff --git a/src/theming.py b/src/theming.py
new file mode 100644
index 00000000..97a09540
--- /dev/null
+++ b/src/theming.py
@@ -0,0 +1,232 @@
+# Copyright 2010-2011 Florent Le Coz <louiz@louiz.org>
+#
+# This file is part of Poezio.
+#
+# Poezio is free software: you can redistribute it and/or modify
+# it under the terms of the zlib license. See the COPYING file.
+
+"""
+Define the variables (colors and some other stuff) that are
+used when drawing the interface.
+
+Colors are numbers from -1 to 7 (if only 8 colors are supported) or -1 to 255
+if 256 colors are available.
+We check the number of available colors at startup, and we load a theme accordingly.
+A 8 color theme should NEVER use colors not in the -1 -> 7 range. We won't check that
+at run time. If the case occurs, the THEME should be fixed.
+XHTML-IM colors are converted to -1 -> 255 colors if available, or directly to
+-1 -> 8 if we are in 8-color-mode.
+
+A pair_color is a background-foreground pair. All possible pairs are not created
+at startup, because that would create 256*256 pairs, and almost all of them
+would never be used.
+So, a theme should define color tuples, like (200, -1), and when they are to
+be used by poezio's interface, they will be created once, and kept in a list for
+later usage.
+A color tuple is of the form (foreground, background, optional)
+A color of -1 means the default color. So if you do not want to have
+a background color, use (x, -1).
+The optional third value of the tuple defines additional information. It
+is a string and can contain one or more of these characteres:
+'b': bold
+'u': underlined
+'x': blink
+
+For example, (200, 208, 'bu') is bold, underlined and pink foreground on orange background.
+
+A theme file is a python file containing two objects named 'theme' and 'theme8', which both are
+instances of two classes (derived from the Theme class) defined in that same file.
+For example, in darktheme.py:
+
+import theming
+class DarkTheme(theming.Theme):
+ COLOR_NORMAL_TEXT = (200, -1)
+ [...]
+
+class DarkTheme8(theming.Theme):
+ COLOR_NORMAL_TEXT = (1, -1)
+ [...]
+
+theme = DarkTheme()
+theme8 = DarkTheme8()
+
+if the command '/theme darktheme' is issued, we import the darktheme.py file
+and set the global variable 'theme' to darktheme.theme.
+
+And in poezio's code we just use theme.COLOR_NORMAL_TEXT etc
+
+Since a theme inherites from the Theme class (defined here), if a color is not defined in a
+theme file, the color is the default one.
+
+Some values in that class are a list of color tuple.
+For example [(1, -1), (2, -1), (3, -1)]
+Such a list SHOULD contain at list one color tuple.
+It is used for example to define color gradient, etc.
+"""
+
+import logging
+log = logging.getLogger(__name__)
+
+from config import config
+
+import curses
+import imp
+import os
+
+class Theme(object):
+ """
+ The theme class, from which all theme should inherit.
+ All of the following value can be replaced in subclasses, in
+ order to create a new theme.
+ Do not edit this file if you want to change the theme to suit your
+ needs. Create a new theme and share it if you think it can be useful
+ for others.
+ """
+ # Message text color
+ COLOR_NORMAL_TEXT = (-1, -1)
+ COLOR_INFORMATION_TEXT = (137, -1)
+ COLOR_HIGHLIGHT_NICK = (208, 22)
+
+ # User list color
+ COLOR_USER_VISITOR = (13, -1)
+ COLOR_USER_PARTICIPANT = (7, -1)
+ COLOR_USER_NONE = (243, -1)
+ COLOR_USER_MODERATOR = (160, -1)
+
+ # nickname colors
+ COLOR_REMOTE_USER = (5, -1)
+
+ # The character printed in color (COLOR_STATUS_*) before the nickname
+ # in the user list
+ CHAR_STATUS = '|'
+
+ # Separators
+ COLOR_VERTICAL_SEPARATOR = (4, -1)
+ COLOR_NEW_TEXT_SEPARATOR = (2, -1)
+ COLOR_MORE_INDICATOR = (6, 4)
+
+ # Time
+ COLOR_TIME_SEPARATOR = (6, -1)
+ COLOR_TIME_LIMITER = (0, -1)
+ CHAR_TIME_LEFT = ''
+ CHAR_TIME_RIGHT = ''
+ COLOR_TIME_NUMBERS = (0, -1)
+
+ # Tabs
+ COLOR_TAB_NORMAL = (7, 4)
+ COLOR_TAB_CURRENT = (7, 6)
+ COLOR_TAB_NEW_MESSAGE = (7, 3)
+ COLOR_TAB_HIGHLIGHT = (7, 9)
+ COLOR_TAB_PRIVATE = (7, 2)
+ COLOR_TAB_DISCONNECTED = (7, 8)
+
+ # Nickname colors
+ LIST_COLOR_NICKNAMES = [(1, -1), (2, -1), (3, -1), (4, -1), (5, -1), (6, -1), (7, -1), (8, -1), (21, -1), (154, -1), (202, -1), (123, -1), (216, -1)]
+ COLOR_OWN_NICK = (254, -1)
+
+ # Status color
+ COLOR_STATUS_XA = (234, 90)
+ COLOR_STATUS_NONE = (234, 4)
+ COLOR_STATUS_DND = (234, 1)
+ COLOR_STATUS_AWAY = (234, 3)
+ COLOR_STATUS_CHAT = (234, 2)
+ COLOR_STATUS_UNAVAILABLE = (-1, 247)
+ COLOR_STATUS_ONLINE = (234, 4)
+
+ # Bars
+ COLOR_INFORMATION_BAR = (7, 4)
+ COLOR_TOPIC_BAR = (7, 4)
+ COLOR_PRIVATE_ROOM_BAR = (-1, 4)
+ COLOR_SCROLLABLE_NUMBER = (214, 4, 'b')
+ COLOR_SELECTED_ROW = (-1, 33)
+ COLOR_PRIVATE_NAME = (-1, 4)
+ COLOR_CONVERSATION_NAME = (4, 4)
+ COLOR_GROUPCHAT_NAME = (7, 4)
+ COLOR_COLUMN_HEADER = (36, 4)
+
+ # Strings for special messages (like join, quit, nick change, etc)
+ # Special messages
+ CHAR_JOIN = '--->'
+ CHAR_QUIT = '<---'
+ CHAR_KICK = '-!-'
+
+ COLOR_JOIN_CHAR = (4, -1)
+ COLOR_QUIT_CHAR = (1, -1)
+ COLOR_KICK_CHAR = (1, -1)
+
+# This is the default theme object, used if no theme is defined in the conf
+theme = Theme()
+
+# a dict "color tuple -> color_pair"
+# Each time we use a color tuple, we check if it has already been used.
+# If not we create a new color_pair and keep it in that dict, to use it
+# the next time.
+curses_colors_dict = {}
+
+def to_curses_attr(color_tuple):
+ """
+ Takes a color tuple (as defined at the top of this file) and
+ returns a valid curses attr that can be passed directly to attron() or attroff()
+ """
+ # extract the color from that tuple
+ if len(color_tuple) == 3:
+ colors = (color_tuple[0], color_tuple[1])
+ else:
+ colors = color_tuple
+
+ # check if we already used these colors
+ try:
+ pair = curses_colors_dict[colors]
+ except KeyError:
+ pair = len(curses_colors_dict) + 1
+ curses.init_pair(pair, colors[0], colors[1])
+ curses_colors_dict[colors] = pair
+ log.debug('New pair: %s (%s)' % (pair, colors,))
+ curses_pair = curses.color_pair(pair)
+ if len(color_tuple) == 3:
+ additional_val = color_tuple[2]
+ if 'b' in additional_val:
+ curses_pair = curses_pair | curses.A_BOLD
+ if 'u' in additional_val:
+ curses_pair = curses_pair | curses.A_UNDERLINE
+ if 'x' in additional_val:
+ curses_pair = curses_pair | curses.A_BLINK
+ return curses_pair
+
+def get_theme():
+ """
+ Returns the current theme
+ """
+ return theme
+
+def reload_theme():
+ themes_dir = config.get('themes_dir', '')
+ themes_dir = themes_dir or\
+ os.path.join(os.environ.get('XDG_DATA_HOME') or\
+ os.path.join(os.environ.get('HOME'), '.local', 'share'),
+ 'poezio', 'themes')
+ try:
+ os.makedirs(themes_dir)
+ except OSError:
+ pass
+ theme_name = config.get('theme', '')
+ if not theme_name:
+ return
+ try:
+ new_theme = imp.load_source('theme', os.path.join(themes_dir, theme_name))
+ except: # TODO warning: theme not found
+ return
+ global theme
+ theme = new_theme
+
+if __name__ == '__main__':
+ """
+ Display some nice text with nice colors
+ """
+ s = curses.initscr()
+ curses.start_color()
+ curses.use_default_colors()
+ s.addstr('%s' % curses.COLORS, to_curses_attr((3, -1, 'x')))
+ s.refresh()
+ s.getkey()
+ curses.endwin()
diff --git a/src/user.py b/src/user.py
index 0fe0bad4..5867e1f3 100644
--- a/src/user.py
+++ b/src/user.py
@@ -10,11 +10,13 @@ Define the user class.
An user is a MUC participant, not a roster contact (see contact.py)
"""
+import curses
+
from random import randrange, choice
from config import config
from datetime import timedelta, datetime
-import curses
-import theme
+
+from theming import get_theme
ROLE_DICT = {
'':0,
@@ -32,7 +34,7 @@ class User(object):
self.last_talked = datetime(1, 1, 1) # The oldest possible time
self.update(affiliation, show, status, role)
self.change_nick(nick)
- self.color = choice(theme.LIST_COLOR_NICKNAMES)
+ self.color = choice(get_theme().LIST_COLOR_NICKNAMES)
self.jid = jid
self.chatstate = None
diff --git a/src/windows.py b/src/windows.py
index 3e607541..a0751c29 100644
--- a/src/windows.py
+++ b/src/windows.py
@@ -33,12 +33,13 @@ from poopt import cut_text
from sleekxmpp.xmlstream.stanzabase import JID
import core
-import theme
import common
import wcwidth
import singleton
import collections
+from theming import get_theme, to_curses_attr
+
# msg is a reference to the corresponding Message tuple. text_start and text_end are the position
# delimiting the text in this line.
# first is a bool telling if this is the first line of the message.
@@ -134,7 +135,7 @@ class Win(object):
elif attr_char == 'b':
self._win.attron(curses.A_BOLD)
elif attr_char in string.digits and attr_char != '':
- self._win.attron(common.curses_color_pair(int(attr_char)))
+ self._win.attron(to_curses_attr((int(attr_char), -1)))
next_attr_char = text.find('\x19')
self.addstr(text)
@@ -145,7 +146,7 @@ class Win(object):
(y, x) = self._win.getyx()
size = self.width-x
if color:
- self.addnstr(' '*size, size, common.curses_color_pair(color))
+ self.addnstr(' '*size, size, to_curses_attr(color))
else:
self.addnstr(' '*size, size)
@@ -159,18 +160,18 @@ class UserList(Win):
def __init__(self):
Win.__init__(self)
self.pos = 0
- self.color_role = {'moderator': theme.COLOR_USER_MODERATOR,
- 'participant':theme.COLOR_USER_PARTICIPANT,
- 'visitor':theme.COLOR_USER_VISITOR,
- 'none':theme.COLOR_USER_NONE,
- '':theme.COLOR_USER_NONE
+ self.color_role = {'moderator': get_theme().COLOR_USER_MODERATOR,
+ 'participant':get_theme().COLOR_USER_PARTICIPANT,
+ 'visitor':get_theme().COLOR_USER_VISITOR,
+ 'none':get_theme().COLOR_USER_NONE,
+ '':get_theme().COLOR_USER_NONE
}
- self.color_show = {'xa':theme.COLOR_STATUS_XA,
- 'none':theme.COLOR_STATUS_NONE,
- '':theme.COLOR_STATUS_NONE,
- 'dnd':theme.COLOR_STATUS_DND,
- 'away':theme.COLOR_STATUS_AWAY,
- 'chat':theme.COLOR_STATUS_CHAT
+ self.color_show = {'xa':get_theme().COLOR_STATUS_XA,
+ 'none':get_theme().COLOR_STATUS_NONE,
+ '':get_theme().COLOR_STATUS_NONE,
+ 'dnd':get_theme().COLOR_STATUS_DND,
+ 'away':get_theme().COLOR_STATUS_AWAY,
+ 'chat':get_theme().COLOR_STATUS_CHAT
}
def scroll_up(self):
@@ -182,7 +183,7 @@ class UserList(Win):
self.pos = 0
def draw_plus(self, y):
- self.addstr(y, self.width-2, '++', common.curses_color_pair(theme.COLOR_MORE_INDICATOR))
+ self.addstr(y, self.width-2, '++', to_curses_attr(get_theme().COLOR_MORE_INDICATOR))
def refresh(self, users):
log.debug('Refresh: %s'%self.__class__.__name__)
@@ -194,11 +195,11 @@ class UserList(Win):
self.pos = len(users)-1
for user in users[self.pos:]:
if not user.role in self.color_role:
- role_col = theme.COLOR_USER_NONE
+ role_col = get_theme().COLOR_USER_NONE
else:
role_col = self.color_role[user.role]
if not user.show in self.color_show:
- show_col = theme.COLOR_STATUS_NONE
+ show_col = get_theme().COLOR_STATUS_NONE
else:
show_col = self.color_show[user.show]
if user.chatstate == 'composing':
@@ -208,9 +209,9 @@ class UserList(Win):
elif user.chatstate == 'paused':
char = 'p'
else:
- char = theme.CHAR_STATUS
- self.addstr(y, 0, char, common.curses_color_pair(show_col))
- self.addstr(y, 1, user.nick[:self.width-2], common.curses_color_pair(role_col))
+ char = get_theme().CHAR_STATUS
+ self.addstr(y, 0, char, to_curses_attr(show_col))
+ self.addstr(y, 1, user.nick[:self.width-2], to_curses_attr(role_col))
y += 1
if y == self.height:
break
@@ -223,9 +224,9 @@ class UserList(Win):
def resize(self, height, width, y, x):
self._resize(height, width, y, x)
- self._win.attron(common.curses_color_pair(theme.COLOR_VERTICAL_SEPARATOR))
+ self._win.attron(to_curses_attr(get_theme().COLOR_VERTICAL_SEPARATOR))
self._win.vline(0, 0, curses.ACS_VLINE, self.height)
- self._win.attroff(common.curses_color_pair(theme.COLOR_VERTICAL_SEPARATOR))
+ self._win.attroff(to_curses_attr(get_theme().COLOR_VERTICAL_SEPARATOR))
class Topic(Win):
def __init__(self):
@@ -240,12 +241,12 @@ class Topic(Win):
msg = topic[:self.width-1]
else:
msg = self._message[:self.width-1]
- self.addstr(0, 0, msg, common.curses_color_pair(theme.COLOR_TOPIC_BAR))
+ self.addstr(0, 0, msg, to_curses_attr(get_theme().COLOR_TOPIC_BAR))
(y, x) = self._win.getyx()
remaining_size = self.width - x
if remaining_size:
self.addnstr(' '*remaining_size, remaining_size,
- common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
self._refresh()
def set_message(self, message):
@@ -262,24 +263,24 @@ class GlobalInfoBar(Win):
comp = lambda x: x.nb
with g_lock:
self._win.erase()
- self.addstr(0, 0, "[", common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(0, 0, "[", to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
sorted_tabs = sorted(self.core.tabs, key=comp)
for tab in sorted_tabs:
color = tab.get_color_state()
if config.get('show_inactive_tabs', 'true') == 'false' and\
- color == theme.COLOR_TAB_NORMAL:
+ color == get_theme().COLOR_TAB_NORMAL:
continue
try:
- self.addstr("%s" % str(tab.nb), common.curses_color_pair(color))
- self.addstr("|", common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr("%s" % str(tab.nb), to_curses_attr(color))
+ self.addstr("|", to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
except: # end of line
break
(y, x) = self._win.getyx()
- self.addstr(y, x-1, '] ', common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(y, x-1, '] ', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
(y, x) = self._win.getyx()
remaining_size = self.width - x
self.addnstr(' '*remaining_size, remaining_size,
- common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
self._refresh()
class InfoWin(Win):
@@ -298,7 +299,7 @@ class InfoWin(Win):
"""
if window.pos > 0:
plus = ' -PLUS(%s)-' % window.pos
- self.addstr(plus, common.curses_color_pair(theme.COLOR_SCROLLABLE_NUMBER))
+ self.addstr(plus, to_curses_attr(get_theme().COLOR_SCROLLABLE_NUMBER))
class PrivateInfoWin(InfoWin):
"""
@@ -315,33 +316,33 @@ class PrivateInfoWin(InfoWin):
self.write_room_name(room)
self.print_scroll_position(window)
self.write_chatstate(chatstate)
- self.finish_line(theme.COLOR_INFORMATION_BAR)
+ self.finish_line(get_theme().COLOR_INFORMATION_BAR)
self._refresh()
def write_room_name(self, room):
jid = JID(room.name)
room_name, nick = jid.bare, jid.resource
- self.addstr(nick, common.curses_color_pair(theme.COLOR_PRIVATE_NAME))
+ self.addstr(nick, to_curses_attr(get_theme().COLOR_PRIVATE_NAME))
txt = ' from room %s' % room_name
- self.addstr(txt, common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(txt, to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
def write_chatstate(self, state):
if state:
- self.addstr(' %s' % (state,), common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(' %s' % (state,), to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
class ConversationInfoWin(InfoWin):
"""
The line above the information window, displaying informations
about the user we are talking to
"""
- color_show = {'xa':theme.COLOR_STATUS_XA,
- 'none':theme.COLOR_STATUS_ONLINE,
- '':theme.COLOR_STATUS_ONLINE,
- 'available':theme.COLOR_STATUS_ONLINE,
- 'dnd':theme.COLOR_STATUS_DND,
- 'away':theme.COLOR_STATUS_AWAY,
- 'chat':theme.COLOR_STATUS_CHAT,
- 'unavailable':theme.COLOR_STATUS_UNAVAILABLE
+ color_show = {'xa':get_theme().COLOR_STATUS_XA,
+ 'none':get_theme().COLOR_STATUS_ONLINE,
+ '':get_theme().COLOR_STATUS_ONLINE,
+ 'available':get_theme().COLOR_STATUS_ONLINE,
+ 'dnd':get_theme().COLOR_STATUS_DND,
+ 'away':get_theme().COLOR_STATUS_AWAY,
+ 'chat':get_theme().COLOR_STATUS_CHAT,
+ 'unavailable':get_theme().COLOR_STATUS_UNAVAILABLE
}
def __init__(self):
@@ -372,7 +373,7 @@ class ConversationInfoWin(InfoWin):
self.write_resource_information(resource)
self.print_scroll_position(window)
self.write_chatstate(chatstate)
- self.finish_line(theme.COLOR_INFORMATION_BAR)
+ self.finish_line(get_theme().COLOR_INFORMATION_BAR)
self._refresh()
def write_resource_information(self, resource):
@@ -384,31 +385,31 @@ class ConversationInfoWin(InfoWin):
else:
presence = resource.get_presence()
color = RosterWin.color_show[presence]
- self.addstr('[', common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
- self.addstr(" ", common.curses_color_pair(color))
- self.addstr(']', common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr('[', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.addstr(" ", to_curses_attr(color))
+ self.addstr(']', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
def write_contact_informations(self, contact):
"""
Write the informations about the contact
"""
if not contact:
- self.addstr("(contact not in roster)", common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr("(contact not in roster)", to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
return
display_name = contact.get_name() or contact.get_bare_jid()
- self.addstr('%s '%(display_name), common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr('%s '%(display_name), to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
def write_contact_jid(self, jid):
"""
Just write the jid that we are talking to
"""
- self.addstr('[', common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
- self.addstr(jid.full, common.curses_color_pair(theme.COLOR_CONVERSATION_NAME))
- self.addstr('] ', common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr('[', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.addstr(jid.full, to_curses_attr(get_theme().COLOR_CONVERSATION_NAME))
+ self.addstr('] ', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
def write_chatstate(self, state):
if state:
- self.addstr(' %s' % (state,), common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(' %s' % (state,), to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
class ConversationStatusMessageWin(InfoWin):
"""
@@ -431,11 +432,11 @@ class ConversationStatusMessageWin(InfoWin):
self._win.erase()
if resource:
self.write_status_message(resource)
- self.finish_line(theme.COLOR_INFORMATION_BAR)
+ self.finish_line(get_theme().COLOR_INFORMATION_BAR)
self._refresh()
def write_status_message(self, resource):
- self.addstr(resource.get_status(), common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(resource.get_status(), to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
class MucInfoWin(InfoWin):
"""
@@ -455,20 +456,20 @@ class MucInfoWin(InfoWin):
self.write_role(room)
if window:
self.print_scroll_position(window)
- self.finish_line(theme.COLOR_INFORMATION_BAR)
+ self.finish_line(get_theme().COLOR_INFORMATION_BAR)
self._refresh()
def write_room_name(self, room):
- self.addstr('[', common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
- self.addstr(room.name, common.curses_color_pair(theme.COLOR_GROUPCHAT_NAME))
- self.addstr('] ', common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr('[', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.addstr(room.name, to_curses_attr(get_theme().COLOR_GROUPCHAT_NAME))
+ self.addstr('] ', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
def write_disconnected(self, room):
"""
Shows a message if the room is not joined
"""
if not room.joined:
- self.addstr(' -!- Not connected ', common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(' -!- Not connected ', to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
def write_own_nick(self, room):
"""
@@ -477,7 +478,7 @@ class MucInfoWin(InfoWin):
nick = room.own_nick
if not nick:
return
- self.addstr(truncate_nick(nick, 13), common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(truncate_nick(nick, 13), to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
def write_role(self, room):
"""
@@ -494,7 +495,7 @@ class MucInfoWin(InfoWin):
if own_user.affiliation != 'none':
txt += own_user.affiliation+', '
txt += own_user.role+')'
- self.addstr(txt, common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(txt, to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
class TextWin(Win):
def __init__(self, lines_nb_limit=config.get('max_lines_in_memory', 2048)):
@@ -559,9 +560,9 @@ class TextWin(Win):
offset = 1 + len(message.str_time)
if nick:
offset += wcwidth.wcswidth(nick) + 2 # + nick + spaces length
- if theme.CHAR_TIME_LEFT:
+ if get_theme().CHAR_TIME_LEFT:
offset += 1
- if theme.CHAR_TIME_RIGHT:
+ if get_theme().CHAR_TIME_RIGHT:
offset += 1
lines = cut_text(txt, self.width-offset)
for line in lines:
@@ -610,7 +611,7 @@ class TextWin(Win):
self._refresh()
def write_line_separator(self):
- self.addnstr('- '*(self.width//2-1)+'-', self.width, common.curses_color_pair(theme.COLOR_NEW_TEXT_SEPARATOR))
+ self.addnstr('- '*(self.width//2-1)+'-', self.width, to_curses_attr(get_theme().COLOR_NEW_TEXT_SEPARATOR))
def write_text(self, y, x, txt):
"""
@@ -626,10 +627,10 @@ class TextWin(Win):
if not nickname:
return
if color:
- self._win.attron(common.curses_color_pair(color))
+ self._win.attron(to_curses_attr(color))
self.addstr(truncate_nick(nickname))
if color:
- self._win.attroff(common.curses_color_pair(color))
+ self._win.attroff(to_curses_attr(color))
self.addstr("> ")
def write_time(self, time):
@@ -672,8 +673,8 @@ class HelpText(Win):
self.txt = txt
with g_lock:
self._win.erase()
- self.addstr(0, 0, self.txt[:self.width-1], common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
- self.finish_line(theme.COLOR_INFORMATION_BAR)
+ self.addstr(0, 0, self.txt[:self.width-1], to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.finish_line(get_theme().COLOR_INFORMATION_BAR)
self._refresh()
def do_command(self, key):
@@ -1034,16 +1035,16 @@ class Input(Win):
text = self.text.replace('\n', '|')
self._win.erase()
if self.color:
- self._win.attron(common.curses_color_pair(self.color))
+ self._win.attron(to_curses_attr(self.color))
displayed_text = text[self.line_pos:self.line_pos+self.width-1]
self.addstr(displayed_text)
if self.color:
(y, x) = self._win.getyx()
size = self.width-x
- self.addnstr(' '*size, size, common.curses_color_pair(self.color))
+ self.addnstr(' '*size, size, to_curses_attr(self.color))
self.addstr(0, wcwidth.wcswidth(displayed_text[:self.pos]), '')
if self.color:
- self._win.attroff(common.curses_color_pair(self.color))
+ self._win.attroff(to_curses_attr(self.color))
self._refresh()
def refresh(self):
@@ -1138,13 +1139,13 @@ class MessageInput(Input):
text = self.text.replace('\n', '|')
self._win.erase()
if self.color:
- self._win.attron(common.curses_color_pair(self.color))
+ self._win.attron(to_curses_attr(self.color))
displayed_text = text[self.line_pos:self.line_pos+self.width-1]
self._win.attrset(0)
self.addstr_colored(displayed_text)
self.addstr(0, wcwidth.wcswidth(displayed_text[:self.pos]), '')
if self.color:
- self._win.attroff(common.curses_color_pair(self.color))
+ self._win.attroff(to_curses_attr(self.color))
self._refresh()
class CommandInput(Input):
@@ -1201,7 +1202,7 @@ class CommandInput(Input):
"""
with g_lock:
self._win.erase()
- self.addstr(self.help_message, common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(self.help_message, to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
cursor_pos = self.pos + len(self.help_message)
if len(self.help_message):
self.addstr(' ')
@@ -1276,7 +1277,7 @@ class VerticalSeparator(Win):
def rewrite_line(self):
with g_lock:
- self._win.vline(0, 0, curses.ACS_VLINE, self.height, common.curses_color_pair(theme.COLOR_VERTICAL_SEPARATOR))
+ self._win.vline(0, 0, curses.ACS_VLINE, self.height, to_curses_attr(get_theme().COLOR_VERTICAL_SEPARATOR))
self._refresh()
def refresh(self):
@@ -1284,14 +1285,14 @@ class VerticalSeparator(Win):
self.rewrite_line()
class RosterWin(Win):
- color_show = {'xa':theme.COLOR_STATUS_XA,
- 'none':theme.COLOR_STATUS_ONLINE,
- '':theme.COLOR_STATUS_ONLINE,
- 'available':theme.COLOR_STATUS_ONLINE,
- 'dnd':theme.COLOR_STATUS_DND,
- 'away':theme.COLOR_STATUS_AWAY,
- 'chat':theme.COLOR_STATUS_CHAT,
- 'unavailable':theme.COLOR_STATUS_UNAVAILABLE
+ color_show = {'xa':get_theme().COLOR_STATUS_XA,
+ 'none':get_theme().COLOR_STATUS_ONLINE,
+ '':get_theme().COLOR_STATUS_ONLINE,
+ 'available':get_theme().COLOR_STATUS_ONLINE,
+ 'dnd':get_theme().COLOR_STATUS_DND,
+ 'away':get_theme().COLOR_STATUS_AWAY,
+ 'chat':get_theme().COLOR_STATUS_CHAT,
+ 'unavailable':get_theme().COLOR_STATUS_UNAVAILABLE
}
def __init__(self):
@@ -1388,22 +1389,22 @@ class RosterWin(Win):
Draw the indicator that shows that
the list is longer than what is displayed
"""
- self.addstr(y, self.width-5, '++++', common.curses_color_pair(theme.COLOR_MORE_INDICATOR))
+ self.addstr(y, self.width-5, '++++', to_curses_attr(get_theme().COLOR_MORE_INDICATOR))
def draw_roster_information(self, roster):
"""
The header at the top
"""
self.addstr('Roster: %s/%s contacts' % (roster.get_nb_connected_contacts(), roster.get_contact_len())\
- , common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
- self.finish_line(theme.COLOR_INFORMATION_BAR)
+ , to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.finish_line(get_theme().COLOR_INFORMATION_BAR)
def draw_group(self, y, group, colored):
"""
Draw a groupname on a line
"""
if colored:
- self._win.attron(common.curses_color_pair(theme.COLOR_SELECTED_ROW))
+ self._win.attron(to_curses_attr(get_theme().COLOR_SELECTED_ROW))
if group.folded:
self.addstr(y, 0, '[+] ')
else:
@@ -1411,7 +1412,7 @@ class RosterWin(Win):
contacts = " (%s/%s)" % (group.get_nb_connected_contacts(), len(group))
self.addstr(y, 4, group.name + contacts)
if colored:
- self._win.attroff(common.curses_color_pair(theme.COLOR_SELECTED_ROW))
+ self._win.attroff(to_curses_attr(get_theme().COLOR_SELECTED_ROW))
self.finish_line()
def draw_contact_line(self, y, contact, colored):
@@ -1438,16 +1439,16 @@ class RosterWin(Win):
else:
display_name = '%s%s' % (contact.get_bare_jid(), nb,)
self.addstr(y, 0, ' ')
- self.addstr(" ", common.curses_color_pair(color))
+ self.addstr(" ", to_curses_attr(color))
if resource:
self.addstr(' [+]' if contact._folded else ' [-]')
self.addstr(' ')
if colored:
- self.addstr(display_name, common.curses_color_pair(theme.COLOR_SELECTED_ROW))
+ self.addstr(display_name, to_curses_attr(get_theme().COLOR_SELECTED_ROW))
else:
self.addstr(display_name)
if contact.get_ask() == 'asked':
- self.addstr('?', common.curses_color_pair(theme.COLOR_HIGHLIGHT_NICK))
+ self.addstr('?', to_curses_attr(get_theme().COLOR_HIGHLIGHT_NICK))
self.finish_line()
def draw_resource_line(self, y, resource, colored):
@@ -1455,9 +1456,9 @@ class RosterWin(Win):
Draw a specific resource line
"""
color = RosterWin.color_show[resource.get_presence()]
- self.addstr(y, 4, " ", common.curses_color_pair(color))
+ self.addstr(y, 4, " ", to_curses_attr(color))
if colored:
- self.addstr(y, 6, resource.get_jid().full, common.curses_color_pair(theme.COLOR_SELECTED_ROW))
+ self.addstr(y, 6, resource.get_jid().full, to_curses_attr(get_theme().COLOR_SELECTED_ROW))
else:
self.addstr(y, 6, resource.get_jid().full)
self.finish_line()
@@ -1482,12 +1483,12 @@ class ContactInfoWin(Win):
presence = resource.get_presence()
else:
presence = 'unavailable'
- self.addstr(0, 0, '%s (%s)'%(jid, presence,), common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
- self.finish_line(theme.COLOR_INFORMATION_BAR)
+ self.addstr(0, 0, '%s (%s)'%(jid, presence,), to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.finish_line(get_theme().COLOR_INFORMATION_BAR)
self.addstr(1, 0, 'Subscription: %s' % (contact.get_subscription(),))
if contact.get_ask():
if contact.get_ask() == 'asked':
- self.addstr(' Ask: %s' % (contact.get_ask(),), common.curses_color_pair(theme.COLOR_HIGHLIGHT_NICK))
+ self.addstr(' Ask: %s' % (contact.get_ask(),), to_curses_attr(get_theme().COLOR_HIGHLIGHT_NICK))
else:
self.addstr(' Ask: %s' % (contact.get_ask(),))
self.finish_line()
@@ -1497,8 +1498,8 @@ class ContactInfoWin(Win):
"""
draw the group information
"""
- self.addstr(0, 0, group.name, common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
- self.finish_line(theme.COLOR_INFORMATION_BAR)
+ self.addstr(0, 0, group.name, to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
+ self.finish_line(get_theme().COLOR_INFORMATION_BAR)
def refresh(self, selected_row):
log.debug('Refresh: %s'%self.__class__.__name__)
@@ -1581,7 +1582,7 @@ class ListWin(Win):
if not txt:
continue
if line is self.lines[self._selected_row]:
- self.addstr(y, x, txt[:size], common.curses_color_pair(theme.COLOR_INFORMATION_BAR))
+ self.addstr(y, x, txt[:size], to_curses_attr(get_theme().COLOR_INFORMATION_BAR))
else:
self.addstr(y, x, txt[:size])
x += size
@@ -1659,7 +1660,7 @@ class ColumnHeaderWin(Win):
txt = col
size = self._columns_sizes[col]
txt += ' ' * (size-len(txt))
- self.addstr(0, x, txt, common.curses_color_pair(theme.COLOR_COLUMN_HEADER))
+ self.addstr(0, x, txt, to_curses_attr(get_theme().COLOR_COLUMN_HEADER))
x += size
self._refresh()