Themes are working, need a little polishing and documentation

This commit is contained in:
louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13 2010-08-20 20:55:42 +00:00
parent dd1d7585f6
commit 3ed25bdfce
5 changed files with 225 additions and 91 deletions

View file

@ -31,6 +31,7 @@ import webbrowser
from datetime import datetime
import common
import theme
from handler import Handler
from config import config
@ -98,6 +99,7 @@ class Gui(object):
'nick': (self.command_nick, _("Usage: /nick <nickname>\nNick: Change your nickname in the current room")),
'say': (self.command_say, _('Usage: /say <message>\nSay: Just send the message. Useful if you want your message to begin with a "/"')),
'whois': (self.command_whois, _('Usage: /whois <nickname>\nWhois: Request many informations about the user.')),
'theme': (self.command_theme, _('Usage: /theme\nTheme: Reload the theme defined in the config file.')),
}
self.key_func = {
@ -193,35 +195,10 @@ class Gui(object):
"""
ncurses initialization
"""
curses.start_color()
theme.init_colors()
curses.noecho()
curses.curs_set(0)
curses.use_default_colors()
stdscr.keypad(True)
curses.init_pair(1, curses.COLOR_WHITE,
curses.COLOR_BLUE)
curses.init_pair(2, curses.COLOR_WHITE, -1) # Visitor
curses.init_pair(3, curses.COLOR_CYAN, -1)
curses.init_pair(4, curses.COLOR_RED, -1) # Admin
curses.init_pair(5, curses.COLOR_BLUE, -1) # Participant
curses.init_pair(6, curses.COLOR_CYAN, -1)
curses.init_pair(7, curses.COLOR_GREEN, -1)
curses.init_pair(8, curses.COLOR_MAGENTA, -1)
curses.init_pair(9, curses.COLOR_YELLOW, -1)
curses.init_pair(10, curses.COLOR_WHITE,
curses.COLOR_CYAN) # current room
curses.init_pair(11, curses.COLOR_WHITE,
curses.COLOR_BLUE) # normal room
curses.init_pair(12, curses.COLOR_WHITE,
curses.COLOR_MAGENTA) # new message room
curses.init_pair(13, curses.COLOR_WHITE,
curses.COLOR_RED) # highlight room
curses.init_pair(14, curses.COLOR_WHITE,
curses.COLOR_YELLOW)
curses.init_pair(15, curses.COLOR_WHITE, # new message in private room
curses.COLOR_GREEN)
curses.init_pair(16, curses.COLOR_YELLOW,
curses.COLOR_BLUE)
def reset_curses(self):
"""
@ -243,7 +220,7 @@ class Gui(object):
"""
Refresh everything
"""
self.current_room().set_color_state(common.ROOM_STATE_CURRENT)
self.current_room().set_color_state(theme.COLOR_TAB_CURRENT)
self.window.refresh(self.rooms)
def join_room(self, room, nick):
@ -251,7 +228,7 @@ class Gui(object):
join the specified room (muc), using the specified nick
"""
r = Room(room, nick, self.window)
self.current_room().set_color_state(11)
self.current_room().set_color_state(theme.COLOR_TAB_NORMAL)
if self.current_room().nb == 0:
self.rooms.append(r)
else:
@ -305,15 +282,15 @@ class Gui(object):
- A Muc with any new message
"""
for room in self.rooms:
if room.color_state == 15:
if room.color_state == theme.COLOR_TAB_PRIVATE:
self.command_win('%s' % room.nb)
return
for room in self.rooms:
if room.color_state == 13:
if room.color_state == theme.COLOR_TAB_HIGHLIGHT:
self.command_win('%s' % room.nb)
return
for room in self.rooms:
if room.color_state == 12:
if room.color_state == theme.COLOR_TAB_NEW_MESSAGE:
self.command_win('%s' % room.nb)
return
@ -321,20 +298,20 @@ class Gui(object):
"""
rotate the rooms list to the right
"""
self.current_room().set_color_state(common.ROOM_STATE_NONE)
self.current_room().set_color_state(theme.COLOR_TAB_NORMAL)
self.current_room().remove_line_separator()
self.rooms.append(self.rooms.pop(0))
self.current_room().set_color_state(common.ROOM_STATE_CURRENT)
self.current_room().set_color_state(theme.COLOR_TAB_CURRENT)
self.refresh_window()
def rotate_rooms_left(self, args=None):
"""
rotate the rooms list to the right
"""
self.current_room().set_color_state(common.ROOM_STATE_NONE)
self.current_room().set_color_state(theme.COLOR_TAB_NORMAL)
self.current_room().remove_line_separator()
self.rooms.insert(0, self.rooms.pop())
self.current_room().set_color_state(common.ROOM_STATE_CURRENT)
self.current_room().set_color_state(theme.COLOR_TAB_CURRENT)
self.refresh_window()
def scroll_page_down(self, args=None):
@ -495,7 +472,7 @@ class Gui(object):
for child in xtag.getTags('status'):
if child.getAttr('code') == '170':
self.add_message_to_room(room, 'Warning: this room is publicly logged')
new_user.color = 2
new_user.color = theme.COLOR_OWN_NICK
else:
change_nick = stanza.getStatusCode() == '303'
kick = stanza.getStatusCode() == '307'
@ -674,6 +651,11 @@ class Gui(object):
nickname = args[0]
self.muc.request_vcard(room.name, nickname)
def command_theme(self, arg):
"""
"""
theme.reload_theme()
def command_win(self, arg):
"""
/win <number>
@ -689,17 +671,17 @@ class Gui(object):
return
if self.current_room().nb == nb:
return
self.current_room().set_color_state(common.ROOM_STATE_NONE)
self.current_room().set_color_state(theme.COLOR_TAB_NORMAL)
self.current_room().remove_line_separator()
start = self.current_room()
self.rooms.append(self.rooms.pop(0))
while self.current_room().nb != nb:
self.rooms.append(self.rooms.pop(0))
if self.current_room() == start:
self.current_room().set_color_state(common.ROOM_STATE_CURRENT)
self.current_room().set_color_state(theme.COLOR_TAB_CURRENT)
self.refresh_window()
return
self.current_room().set_color_state(common.ROOM_STATE_CURRENT)
self.current_room().set_color_state(theme.COLOR_TAB_CURRENT)
self.refresh_window()
def command_kick(self, arg):

View file

@ -23,6 +23,7 @@ from logging import logger
from message import Message
import common
import theme
class Room(object):
"""
@ -32,7 +33,7 @@ class Room(object):
self.jid = jid # used for a private chat. None if it's a MUC
self.name = name
self.own_nick = nick
self.color_state = common.ROOM_STATE_NONE # color used in RoomInfo
self.color_state = theme.COLOR_TAB_NORMAL # color used in RoomInfo
self.nb = Room.number # number used in RoomInfo
Room.number += 1
self.joined = False # false until self presence is received
@ -68,25 +69,25 @@ class Room(object):
"""
Set the tab color and returns the txt color
"""
color = None
color = theme.COLOR_NORMAL_TEXT
if not time and nickname and nickname.encode('utf-8') != self.own_nick and self.joined: # do the highlight
try:
if self.own_nick in txt.encode('utf-8'):
self.set_color_state(common.ROOM_STATE_HL)
color = 4
self.set_color_state(theme.COLOR_TAB_HIGHLIGHT)
color = theme.COLOR_HIGHLIGHT_TEXT
except UnicodeDecodeError:
try:
if self.own_nick in txt:
self.set_color_state(common.ROOM_STATE_HL)
color = 4
self.set_color_state(theme.COLOR_TAB_HIGHLIGHT)
color = theme.COLOR_HIGHLIGHT_TEXT
except:
pass
else:
highlight_words = config.get('highlight_on', '').split(':')
for word in highlight_words:
if word.lower() in txt.lower() and word != '':
self.set_color_state(common.ROOM_STATE_HL)
color = 4
self.set_color_state(theme.COLOR_TAB_HIGHLIGHT)
color = theme.COLOR_HIGHLIGHT_TEXT
break
return color
@ -100,20 +101,20 @@ class Room(object):
user = self.get_user_by_name(nickname) if nickname is not None else None
if user:
user.set_last_talked(datetime.now())
color = None
color = theme.COLOR_NORMAL_TEXT
if not time and nickname and\
nickname != self.own_nick and\
self.color_state != common.ROOM_STATE_CURRENT:
if not self.jid and self.color_state != common.ROOM_STATE_HL:
self.set_color_state(common.ROOM_STATE_MESSAGE)
self.color_state != theme.COLOR_TAB_CURRENT:
if not self.jid and self.color_state != theme.COLOR_TAB_HIGHLIGHT:
self.set_color_state(theme.COLOR_TAB_NEW_MESSAGE)
elif self.jid:
self.set_color_state(common.ROOM_STATE_PRIVATE)
self.set_color_state(theme.COLOR_TAB_PRIVATE)
if not nickname:
color = 8
color = theme.COLOR_INFORMATION_TEXT
else:
color = self.do_highlight(txt, time, nickname)
if time: # History messages are colored to be distinguished
color = 8
color = theme.COLOR_INFORMATION_TEXT
time = time if time is not None else datetime.now()
self.messages.append(Message(txt, time, nickname, user, color))

131
src/theme.py Normal file
View file

@ -0,0 +1,131 @@
# -*- coding:utf-8 -*-
#
# Copyright 2010 Le Coz Florent <louizatakk@fedoraproject.org>
#
# This file is part of Poezio.
#
# Poezio is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# Poezio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Poezio. If not, see <http://www.gnu.org/licenses/>.
"""
Define the variables (colors and some other stuff) that are
used when drawing the interface (mainly colors)
"""
import curses
import inspect
import imp
from config import config
## Define the default colors
## Do not change these colors, create a theme file instead.
# Message text color
COLOR_NORMAL_TEXT = 0
COLOR_INFORMATION_TEXT = 76
COLOR_HIGHLIGHT_TEXT = 77
# User list color
COLOR_USER_VISITOR = 78
COLOR_USER_PARTICIPANT = 73
COLOR_USER_NONE = 80
COLOR_USER_MODERATOR = 77
# Separators
COLOR_VERTICAL_SEPARATOR = 73
COLOR_NEW_TEXT_SEPARATOR = 75
# Time
COLOR_TIME_SEPARATOR = 79
COLOR_TIME_BRACKETS = 74
COLOR_TIME_NUMBERS = 0
# Tabs
COLOR_TAB_NORMAL = 15
COLOR_TAB_CURRENT = 24
COLOR_TAB_NEW_MESSAGE = 42
COLOR_TAB_HIGHLIGHT = 51
COLOR_TAB_PRIVATE = 33
# Nickname colors
LIST_COLOR_NICKNAMES = [
73, 74, 75, 76, 77, 78, 79
]
COLOR_OWN_NICK = 72
# Status color
COLOR_STATUS_XA = 40
COLOR_STATUS_NONE = 0
COLOR_STATUS_DND = 50
COLOR_STATUS_AWAY = 70
COLOR_STATUS_CHAT = 30
# Bars
COLOR_INFORMATION_BAR = 15
COLOR_TOPIC_BAR = 15
COLOR_PRIVATE_ROOM_BAR = 33
COLOR_SCROLLABLE_NUMBER = 16
def init_colors():
"""
Initilization of all the available ncurses colors
"""
curses.start_color()
curses.use_default_colors()
colors_list = [
curses.COLOR_BLACK,
curses.COLOR_BLUE,
curses.COLOR_CYAN,
curses.COLOR_GREEN,
curses.COLOR_MAGENTA,
curses.COLOR_RED,
curses.COLOR_WHITE,
curses.COLOR_YELLOW,
-1
]
cpt = 0
for i in colors_list:
for y in colors_list:
curses.init_pair(cpt, y, i)
cpt += 1
reload_theme()
def reload_theme():
current_module = __import__(inspect.getmodulename(__file__))
path = config.get('theme_file', '../default.theme')
try:
theme = imp.load_source('theme', path)
except:
return
for var in dir(theme):
if var.startswith('COLOR_'):
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()
for i in xrange(80):
s.attron(curses.color_pair(i))
s.addstr(str(i))
s.attroff(curses.color_pair(i))
s.addstr(' ')
s.refresh()
s.getch()
s.endwin()

View file

@ -16,10 +16,11 @@
# You should have received a copy of the GNU General Public License
# along with Poezio. If not, see <http://www.gnu.org/licenses/>.
from random import randrange
from random import randrange, choice
from config import config
from datetime import timedelta, datetime
import curses
import theme
class User(object):
"""
@ -29,7 +30,7 @@ class User(object):
self.last_talked = None
self.update(affiliation, show, status, role)
self.change_nick(nick)
self.color = randrange(3, 10) # assign a random color
self.color = choice(theme.LIST_COLOR_NICKNAMES)
def update(self, affiliation, show, status, role):
self.affiliation = affiliation
@ -60,5 +61,3 @@ class User(object):
def __repr__(self):
return ">%s<" % (self.nick.decode('utf-8'))
# return "<user.User object nick:%s show:%s(%s) status:%s affiliation:%s>"\
# % (self.nick.decode('utf-8'), self.show, type(self.show), self.status, self.affiliation)

View file

@ -29,6 +29,7 @@ from config import config
from threading import Lock
from message import Line
import theme
g_lock = Lock()
@ -59,16 +60,16 @@ class UserList(Win):
def __init__(self, height, width, y, x, parent_win, visible):
Win.__init__(self, height, width, y, x, parent_win)
self.visible = visible
self.color_role = {'moderator': 4,
'participant':5,
'visitor':2,
'none':3
self.color_role = {'moderator': theme.COLOR_USER_MODERATOR,
'participant':theme.COLOR_USER_PARTICIPANT,
'visitor':theme.COLOR_USER_VISITOR,
'none':theme.COLOR_USER_NONE
}
self.color_show = {'xa':12,
'None':8,
'dnd':13,
'away':14,
'chat':15
self.color_show = {'xa':theme.COLOR_STATUS_XA,
'None':theme.COLOR_STATUS_NONE,
'dnd':theme.COLOR_STATUS_DND,
'away':theme.COLOR_STATUS_AWAY,
'chat':theme.COLOR_STATUS_CHAT
}
def refresh(self, users):
@ -95,11 +96,11 @@ class UserList(Win):
try:
role_col = self.color_role[user.role]
except KeyError:
role_col = 5
role_col = theme.COLOR_USER_NONE
try:
show_col = self.color_show[user.show]
except KeyError:
show_col = 8
show_col = theme.COLOR_STATUS_NONE
self.win.attron(curses.color_pair(show_col))
self.win.addnstr(y, 0, " ", 1)
self.win.attroff(curses.color_pair(show_col))
@ -136,10 +137,10 @@ class Topic(Win):
self.win.erase()
if not jid:
try:
self.win.addstr(0, 0, topic, curses.color_pair(1))
self.win.addstr(0, 0, topic, curses.color_pair(theme.COLOR_TOPIC_BAR))
while True:
try:
self.win.addch(' ', curses.color_pair(1))
self.win.addch(' ', curses.color_pair(theme.COLOR_TOPIC_BAR))
except:
break
except:
@ -149,7 +150,7 @@ class Topic(Win):
nick = '/'.join(jid.split('/')[1:])
topic = _('%(nick)s from room %(room)s' % {'nick': nick, 'room':room})
self.win.addnstr(0, 0, topic.encode('utf-8') + " "*(self.width-len(topic)), self.width-1
, curses.color_pair(15))
, curses.color_pair(theme.COLOR_PRIVATE_ROOM_BAR))
self.win.refresh()
g_lock.release()
@ -169,7 +170,7 @@ class RoomInfo(Win):
down
"""
if current_room.pos > 0:
self.win.addstr(' -PLUS(%s)-' % current_room.pos, curses.color_pair(16) | curses.A_BOLD)
self.win.addstr(' -PLUS(%s)-' % current_room.pos, curses.color_pair(theme.COLOR_SCROLLABLE_NUMBER) | curses.A_BOLD)
def refresh(self, rooms, current):
if not self.visible:
@ -179,28 +180,28 @@ class RoomInfo(Win):
g_lock.acquire()
self.win.erase()
self.win.addnstr(0, 0, "[", self.width
,curses.color_pair(1))
,curses.color_pair(theme.COLOR_INFORMATION_BAR))
sorted_rooms = sorted(rooms, compare_room)
for room in sorted_rooms:
color = room.color_state
try:
self.win.addstr("%s" % str(room.nb), curses.color_pair(color))
self.win.addstr(u"|".encode('utf-8'), curses.color_pair(1))
self.win.addstr(u"|".encode('utf-8'), curses.color_pair(theme.COLOR_INFORMATION_BAR))
except: # end of line
break
(y, x) = self.win.getyx()
try:
self.win.addstr(y, x-1, '] '+ current.name, curses.color_pair(1))
self.win.addstr(y, x-1, '] '+ current.name, curses.color_pair(theme.COLOR_INFORMATION_BAR))
except:
try:
self.win.addstr(y, x-1, '] '+ current.name.encode('utf-8'), curses.color_pair(1))
self.win.addstr(y, x-1, '] '+ current.name.encode('utf-8'), curses.color_pair(theme.COLOR_INFORMATION_BAR))
except:
pass
pass
self.print_scroll_position(current)
while True:
try:
self.win.addstr(' ', curses.color_pair(1))
self.win.addstr(' ', curses.color_pair(theme.COLOR_INFORMATION_BAR))
except:
break
self.win.refresh()
@ -315,9 +316,9 @@ class TextWin(Win):
def write_line_separator(self):
"""
"""
self.win.attron(curses.color_pair(7))
self.win.attron(curses.color_pair(theme.COLOR_NEW_TEXT_SEPARATOR))
self.win.addstr(' -'*(self.width/2))
self.win.attroff(curses.color_pair(7))
self.win.attroff(curses.color_pair(theme.COLOR_NEW_TEXT_SEPARATOR))
def write_text(self, y, x, txt, color):
"""
@ -349,15 +350,35 @@ class TextWin(Win):
"""
Write the date on the yth line of the window
"""
self.win.addnstr('['+time.strftime("%H"), 3)
self.win.attron(curses.color_pair(9))
self.win.attron(curses.color_pair(theme.COLOR_TIME_BRACKETS))
self.win.addnstr('[', 1)
self.win.attroff(curses.color_pair(theme.COLOR_TIME_BRACKETS))
self.win.attron(curses.color_pair(theme.COLOR_TIME_NUMBERS))
self.win.addnstr(time.strftime("%H"), 2)
self.win.attroff(curses.color_pair(theme.COLOR_TIME_NUMBERS))
self.win.attron(curses.color_pair(theme.COLOR_TIME_SEPARATOR))
self.win.addnstr(':', 1)
self.win.attroff(curses.color_pair(9))
self.win.addnstr(time.strftime('%M'), 2)
self.win.attron(curses.color_pair(9))
self.win.attroff(curses.color_pair(theme.COLOR_TIME_SEPARATOR))
self.win.attron(curses.color_pair(theme.COLOR_TIME_NUMBERS))
self.win.addnstr(time.strftime("%M"), 2)
self.win.attroff(curses.color_pair(theme.COLOR_TIME_NUMBERS))
self.win.attron(curses.color_pair(theme.COLOR_TIME_SEPARATOR))
self.win.addnstr(':', 1)
self.win.attroff(curses.color_pair(9))
self.win.addnstr(time.strftime('%S') + "] ", 4)
self.win.attroff(curses.color_pair(theme.COLOR_TIME_SEPARATOR))
self.win.attron(curses.color_pair(theme.COLOR_TIME_NUMBERS))
self.win.addnstr(time.strftime('%S'), 2)
self.win.attroff(curses.color_pair(theme.COLOR_TIME_NUMBERS))
self.win.attron(curses.color_pair(theme.COLOR_TIME_BRACKETS))
self.win.addstr(']')
self.win.attroff(curses.color_pair(theme.COLOR_TIME_BRACKETS))
self.win.addstr(' ')
def resize(self, height, width, y, x, stdscr, visible):
self.visible = visible
@ -726,9 +747,9 @@ class Window(object):
else:
visible = True
if visible:
stdscr.attron(curses.color_pair(5))
stdscr.attron(curses.color_pair(theme.COLOR_VERTICAL_SEPARATOR))
stdscr.vline(1, 9*(self.width/10), curses.ACS_VLINE, self.height-2)
stdscr.attroff(curses.color_pair(5))
stdscr.attroff(curses.color_pair(theme.COLOR_VERTICAL_SEPARATOR))
self.user_win = UserList(self.height-3, (self.width/10)-1, 1, 9*(self.width/10)+1, stdscr, visible)
self.topic_win = Topic(1, self.width, 0, 0, stdscr, visible)
self.info_win = RoomInfo(1, self.width, self.height-2, 0, stdscr, visible)
@ -745,9 +766,9 @@ class Window(object):
else:
visible = True
if visible:
stdscr.attron(curses.color_pair(5))
stdscr.attron(curses.color_pair(theme.COLOR_VERTICAL_SEPARATOR))
stdscr.vline(1, 9*(self.width/10), curses.ACS_VLINE, self.height-2)
stdscr.attroff(curses.color_pair(5))
stdscr.attroff(curses.color_pair(theme.COLOR_VERTICAL_SEPARATOR))
text_width = (self.width/10)*9;
self.topic_win.resize(1, self.width, 0, 0, stdscr, visible)
self.info_win.resize(1, self.width, self.height-2, 0, stdscr, visible)