Totale recode de l'affichage du texte, resultat : 0 BLINK (jamais, nada, quedalle), c'est plus simple (si si), et y'a plus de probleme de melange des messages entre salon. BEST COMMIT EVER. fixed #1171

This commit is contained in:
louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13 2010-06-10 01:17:59 +00:00
parent 41e7437d65
commit fa4fbeb23c
3 changed files with 368 additions and 210 deletions

View file

@ -38,24 +38,29 @@ from config import config
from window import Window from window import Window
from user import User from user import User
from room import Room from room import Room
from message import Message
from common import debug
def doupdate():
debug("doupdate")
curses.doupdate()
class Gui(object): class Gui(object):
""" """
User interface using ncurses User interface using ncurses
""" """
def __init__(self, stdscr=None, muc=None): def __init__(self, stdscr=None, muc=None):
self.room_number = 0
self.init_curses(stdscr) self.init_curses(stdscr)
self.stdscr = stdscr self.stdscr = stdscr
self.rooms = [Room('Info', '', self.next_room_number())]
self.window = Window(stdscr) self.window = Window(stdscr)
self.window.new_room(self.current_room()) # self.window.new_room(self.current_room())
self.window.refresh(self.rooms) # self.window.refresh(self.rooms)
self.rooms = [Room('Info', '', self.window)]
self.muc = muc self.muc = muc
self.commands = { self.commands = {
'help': (self.command_help, _('OLOL, this is SOOO recursive')), 'help': (self.command_help, _('That.')),
'join': (self.command_join, _("""Usage: /join [room_name][/nick] 'join': (self.command_join, _("""Usage: /join [room_name][/nick]
[password]\nJoin: Join the specified room. You can specify a nickname after a [password]\nJoin: Join the specified room. You can specify a nickname after a
slash (/). If no nickname is specified, you will use the default_nick in the slash (/). If no nickname is specified, you will use the default_nick in the
@ -132,6 +137,8 @@ Avail: Sets your availability to available and (optional) sets your status
"KEY_END": self.window.input.key_end, "KEY_END": self.window.input.key_end,
"KEY_HOME": self.window.input.key_home, "KEY_HOME": self.window.input.key_home,
"KEY_DOWN": self.window.input.key_down, "KEY_DOWN": self.window.input.key_down,
"KEY_PPAGE": self.scroll_page_up,
"KEY_NPAGE": self.scroll_page_down,
"KEY_DC": self.window.input.key_dc, "KEY_DC": self.window.input.key_dc,
"KEY_F(5)": self.rotate_rooms_left, "KEY_F(5)": self.rotate_rooms_left,
"KEY_F(6)": self.rotate_rooms_right, "KEY_F(6)": self.rotate_rooms_right,
@ -154,12 +161,14 @@ Avail: Sets your availability to available and (optional) sets your status
main loop waiting for the user to press a key main loop waiting for the user to press a key
""" """
while 1: while 1:
stdscr.leaveok(1) # stdscr.leaveok(1)
curses.doupdate() doupdate()
try: try:
key = stdscr.getkey() key = stdscr.getkey()
except: except:
continue continue
from common import debug
# debug(str(key))
if str(key) in self.key_func.keys(): if str(key) in self.key_func.keys():
self.key_func[key]() self.key_func[key]()
elif str(key) == 'KEY_RESIZE': elif str(key) == 'KEY_RESIZE':
@ -186,13 +195,13 @@ Avail: Sets your availability to available and (optional) sets your status
key = key+stdscr.getkey() key = key+stdscr.getkey()
self.window.do_command(key) self.window.do_command(key)
def next_room_number(self): # def next_room_number(self):
""" # """
Increments the room number and returns the new number # Increments the room number and returns the new number
""" # """
nb = self.room_number # nb = self.room_number
self.room_number += 1 # self.room_number += 1
return nb # return nb
def current_room(self): def current_room(self):
""" """
@ -215,6 +224,7 @@ Avail: Sets your availability to available and (optional) sets your status
""" """
curses.start_color() curses.start_color()
curses.noecho() curses.noecho()
curses.curs_set(0)
# curses.cbreak() # curses.cbreak()
# curses.raw() # curses.raw()
curses.use_default_colors() curses.use_default_colors()
@ -262,7 +272,7 @@ Avail: Sets your availability to available and (optional) sets your status
""" """
join the specified room (muc), using the specified nick join the specified room (muc), using the specified nick
""" """
r = Room(room, nick, self.next_room_number()) r = Room(room, nick, self.window)
self.current_room().set_color_state(11) self.current_room().set_color_state(11)
if self.current_room().nb == 0: if self.current_room().nb == 0:
self.rooms.append(r) self.rooms.append(r)
@ -273,7 +283,7 @@ Avail: Sets your availability to available and (optional) sets your status
break break
while self.current_room().nb != r.nb: while self.current_room().nb != r.nb:
self.rooms.insert(0, self.rooms.pop()) self.rooms.insert(0, self.rooms.pop())
self.window.new_room(r) # self.window.new_room(r)
self.window.refresh(self.rooms) self.window.refresh(self.rooms)
def auto_completion(self): def auto_completion(self):
@ -298,6 +308,14 @@ Avail: Sets your availability to available and (optional) sets your status
self.rooms.insert(0, self.rooms.pop()) self.rooms.insert(0, self.rooms.pop())
self.window.refresh(self.rooms) self.window.refresh(self.rooms)
def scroll_page_down(self, args=None):
self.current_room().scroll_down()
self.window.text_win.refresh(self.current_room())
def scroll_page_up(self, args=None):
self.current_room().scroll_up()
self.window.text_win.refresh(self.current_room())
def room_error(self, room, error, msg): def room_error(self, room, error, msg):
""" """
Display the error on the room window Display the error on the room window
@ -306,12 +324,10 @@ Avail: Sets your availability to available and (optional) sets your status
code = error.getAttr('code') code = error.getAttr('code')
typ = error.getAttr('type') typ = error.getAttr('type')
body = error.getTag('text').getData() body = error.getTag('text').getData()
self.add_info(room, _('Error: %(code)s-%(msg)s: %(body)s' % self.add_message_to_room(room, _('Error: %(code)s-%(msg)s: %(body)s' %
{'msg':msg, 'code':code, 'body':body})) {'msg':msg, 'code':code, 'body':body}))
if code == '401': if code == '401':
self.add_info(room, _("""To provide a password in order room.add(_('To provide a password in order to join the room, type "/join / password" (replace "password" by the real password)'))
to join the room, type "/join / password" (replace "password"
by the real password)"""))
def room_message(self, stanza, date=None): def room_message(self, stanza, date=None):
""" """
@ -335,21 +351,27 @@ Avail: Sets your availability to available and (optional) sets your status
subject = stanza.getSubject() subject = stanza.getSubject()
if subject: if subject:
if nick_from: if nick_from:
self.add_info(room, _("""%(nick)s changed the subject to: self.add_message_to_room(room, _("%(nick)s changed the subject to: %(subject)s") % {'nick':nick_from, 'subject':subject}, date)
%(subject)s""") % {'nick':nick_from, 'subject':subject}, date) # self.add_info(room, _("""%(nick)s changed the subject to:
# %(subject)s""") % {'nick':nick_from, 'subject':subject}, date)
else: else:
self.add_info(room, _("The subject is: %(subject)s") % self.add_message_to_room(room, _("The subject is: %(subject)s") % {'subject':subject}, date)
{'subject':subject}, date) # self.add_info(room, _("The subject is: %(subject)s") %
# {'subject':subject}, date)
room.topic = subject.encode('utf-8').replace('\n', '|') room.topic = subject.encode('utf-8').replace('\n', '|')
if room == self.current_room(): if room == self.current_room():
self.window.topic_win.refresh(room.topic) self.window.topic_win.refresh(room.topic)
elif body: elif body:
if body.startswith('/me '): if body.startswith('/me '):
self.add_info(room, nick_from + ' ' + body[4:], date) # FIXME, it should be LIKE an information
self.add_message_to_room(room, nick_from + ' ' + body[4:], date)
# self.add_info(room, nick_from + ' ' + body[4:], date)
else: else:
self.add_message(room, nick_from, body, date, delayed) date = date if delayed == True else None
self.add_message_to_room(room, body, date, nick_from)
# self.add_message(room, nick_from, body, date, delayed)
self.window.input.refresh() self.window.input.refresh()
curses.doupdate() doupdate()
def room_presence(self, stanza): def room_presence(self, stanza):
""" """
@ -374,10 +396,14 @@ Avail: Sets your availability to available and (optional) sets your status
role)) role))
if from_nick.encode('utf-8') == room.own_nick: if from_nick.encode('utf-8') == room.own_nick:
room.joined = True room.joined = True
self.add_info(room, _("Your nickname is %s") % (from_nick)) self.add_message_to_room(room, _("Your nickname is %s") % (from_nick))
# self.add_info(room, _("Your nickname is %s") % (from_nick))
else: else:
self.add_info(room, _("%s is in the room") % self.add_message_to_room(room, _("%s is in the room") %
(from_nick.encode('utf-8'))) (from_nick# .encode('utf-8')
))
# self.add_info(room, _("%s is in the room") %
# (from_nick.encode('utf-8')))
else: else:
change_nick = stanza.getStatusCode() == '303' change_nick = stanza.getStatusCode() == '303'
kick = stanza.getStatusCode() == '307' kick = stanza.getStatusCode() == '307'
@ -388,17 +414,18 @@ Avail: Sets your availability to available and (optional) sets your status
show, status, role)) show, status, role))
hide_exit_join = config.get('hide_exit_join', -1) hide_exit_join = config.get('hide_exit_join', -1)
if hide_exit_join != 0: if hide_exit_join != 0:
self.add_info(room, _("""%(nick)s joined the self.add_message_to_room(room, _("%(nick)s joined the room %(roomname)s") % {'nick':from_nick, 'roomname': room.name})
room %(roomname)s""") % {'nick':from_nick, 'roomname': room.name}) # self.add_info(room, _("%(nick)s joined the room %(roomname)s") % {'nick':from_nick, 'roomname': room.name})
# nick change # nick change
elif change_nick: elif change_nick:
if user.nick == room.own_nick: if user.nick == room.own_nick:
room.own_nick = stanza.getNick().encode('utf-8') room.own_nick = stanza.getNick().encode('utf-8')
user.change_nick(stanza.getNick()) user.change_nick(stanza.getNick())
self.add_info(room, self.add_message_to_room(room, _('%(old)s is now known as %(new)s') % {'old':from_nick, 'new':stanza.getNick()})
_('%(old)s is now known as %(new)s') % # self.add_info(room,
{'old':from_nick, # _('%(old)s is now known as %(new)s') %
'new':stanza.getNick()}) # {'old':from_nick,
# 'new':stanza.getNick()})
# kick # kick
elif kick: elif kick:
room.users.remove(user) room.users.remove(user)
@ -413,72 +440,87 @@ Avail: Sets your availability to available and (optional) sets your status
if from_nick == room.own_nick: # we are kicked if from_nick == room.own_nick: # we are kicked
room.disconnect() room.disconnect()
if by: if by:
self.add_info(room, _("""You have been kicked by self.add_message_to_room(room, _("You have been kicked by %(by)s. Reason: %(reason)s") % {'by':by, 'reason':reason})
%(by)s. Reason: %(reason)s""") % {'by':by, 'reason':reason}) # self.add_info(room, _("""You have been kicked by
# %(by)s. Reason: %(reason)s""") % {'by':by, 'reason':reason})
else: else:
self.add_info(room, _("""You have been self.add_message_to_room(room, _("You have been kicked. Reason: %s") % (reason))
kicked. Reason: %s""") % (reason)) # self.add_info(room, _("""You have been
# kicked. Reason: %s""") % (reason))
else: else:
if by: if by:
self.add_info(room, _("""%(nick)s has been kicked self.add_message_to_room(room, _("%(nick)s has been kicked by %(by)s. Reason: %(reason)s") % {'nick':from_nick, 'by':by, 'reason':reason})
by %(by)s. Reason: %(reason)s""") % # self.add_info(room, _("""%(nick)s has been kicked
{'nick':from_nick, 'by':by, 'reason':reason}) # by %(by)s. Reason: %(reason)s""") %
# {'nick':from_nick, 'by':by, 'reason':reason})
else: else:
self.add_info(room, _("""%(nick)s has been kicked. self.add_message_to_room(room, _("%(nick)s has been kicked. Reason: %(reason)s") % {'nick':from_nick, 'reason':reason})
Reason: %(reason)s""") % # self.add_info(room, _("""%(nick)s has been kicked.
{'nick':from_nick, 'reason':reason}) # Reason: %(reason)s""") %
# {'nick':from_nick, 'reason':reason})
# user quit # user quit
elif status == 'offline' or role == 'none': elif status == 'offline' or role == 'none':
room.users.remove(user) room.users.remove(user)
hide_exit_join = config.get('hide_exit_join', -1)\ hide_exit_join = config.get('hide_exit_join', -1) if config.get('hide_exit_join', -1) >= -1 else -1
if config.get('hide_exit_join', -1) >= -1\ if hide_exit_join == -1 or user.has_talked_since(hide_exit_join):
else -1 self.add_message_to_room(room, _('%s has left the room') % (from_nick))
if hide_exit_join == -1 or \ # self.add_info(room, _('%s has left the room') % (from_nick))
user.has_talked_since(hide_exit_join):
self.add_info(room, _('%s has left the room') % (from_nick))
# status change # status change
else: else:
user.update(affiliation, show, status, role) user.update(affiliation, show, status, role)
hide_status_change = config.get('hide_status_change', -1)\ hide_status_change = config.get('hide_status_change', -1) if config.get('hide_status_change', -1) >= -1 else -1
if config.get('hide_status_change', -1) >= -1\
else -1
if hide_status_change == -1 or \ if hide_status_change == -1 or \
user.has_talked_since(hide_status_change) or\ user.has_talked_since(hide_status_change) or\
user.nick == room.own_nick: user.nick == room.own_nick:
self.add_info(room, _('%(nick)s changed his/her status : %(a)s, %(b)s, %(c)s, %(d)s') % {'nick':from_nick, 'a':affiliation, 'b':role, 'c':show, 'd':status}) self.add_message_to_room(room, _('%(nick)s changed his/her status : %(a)s, %(b)s, %(c)s, %(d)s') % {'nick':from_nick, 'a':affiliation, 'b':role, 'c':show, 'd':status})
# self.add_info(room, _('%(nick)s changed his/her status : %(a)s, %(b)s, %(c)s, %(d)s') % {'nick':from_nick, 'a':affiliation, 'b':role, 'c':show, 'd':status})
if room == self.current_room(): if room == self.current_room():
self.window.user_win.refresh(room.users) self.window.user_win.refresh(room.users)
self.window.input.refresh() self.window.input.refresh()
curses.doupdate() doupdate()
def add_info(self, room, info, date=None): def add_message_to_room(self, room, txt, time=None, nickname=None):
""" """
add a new information in the specified room Add the message to the room and refresh the associated component
(displays it immediately AND saves it for redisplay of the interface
in futur refresh)
""" """
if not date: room.add_message(txt, time, nickname)
date = datetime.now()
msg = room.add_info(info, date)
self.window.text_win.add_line(room, (date, msg))
if room.name == self.current_room().name:
self.window.text_win.refresh(room.name)
self.window.input.refresh()
curses.doupdate()
def add_message(self, room, nick_from, body, date=None, delayed=False):
"""
Just add a message
"""
if not date:
date = datetime.now()
color = room.add_message(nick_from, body, date)
self.window.text_win.add_line(room, (date, nick_from.encode('utf-8'), body.encode('utf-8'), color))
if room == self.current_room(): if room == self.current_room():
self.window.text_win.refresh(room.name) self.window.text_win.refresh(room)
elif not delayed: # elif not delayed:
else:
self.window.info_win.refresh(self.rooms, self.current_room()) self.window.info_win.refresh(self.rooms, self.current_room())
# TODO
# def add_info(self, room, info, date=None):
# """
# add a new information in the specified room
# (displays it immediately AND saves it for redisplay
# in futur refresh)
# """
# if not date:
# date = datetime.now()
# msg = room.add_info(info, date)
# self.window.text_win.add_line(room, (date, msg))
# if room.name == self.current_room().name:
# self.window.text_win.refresh(room.name)
# self.window.input.refresh()
# doupdate()
# def add_message(self, room, nick_from, body, date=None, delayed=False):
# """
# Just add a message
# """
# if not date:
# date = datetime.now()
# color = room.add_message(nick_from, body, date)
# self.window.text_win.add_line(room, (date, nick_from.encode('utf-8'), body.encode('utf-8'), color))
# if room == self.current_room():
# self.window.text_win.refresh(room.name)
# elif not delayed:
# self.window.info_win.refresh(self.rooms, self.current_room())
def execute(self): def execute(self):
""" """
Execute the /command or just send the line on the current room Execute the /command or just send the line on the current room
@ -496,11 +538,12 @@ Avail: Sets your availability to available and (optional) sets your status
func(args) func(args)
return return
else: else:
self.add_info(self.current_room(), _("Error: unknown command (%s)") % (command)) self.add_message_to_room(self.current_room(), _("Error: unknown command (%s)") % (command))
# self.add_info(self.current_room(), _("Error: unknown command (%s)") % (command))
elif self.current_room().name != 'Info': elif self.current_room().name != 'Info':
self.muc.send_message(self.current_room().name, line) self.muc.send_message(self.current_room().name, line)
self.window.input.refresh() self.window.input.refresh()
curses.doupdate() doupdate()
def command_help(self, args): def command_help(self, args):
""" """
@ -517,7 +560,8 @@ Avail: Sets your availability to available and (optional) sets your status
msg = self.commands[args[0]][1] msg = self.commands[args[0]][1]
else: else:
msg = _('Unknown command: %s') % args[0] msg = _('Unknown command: %s') % args[0]
self.add_info(room, msg) self.add_message_to_room(room, msg)
# self.add_info(room, msg)
def command_win(self, args): def command_win(self, args):
""" """
@ -648,7 +692,8 @@ Avail: Sets your availability to available and (optional) sets your status
config.set_and_save(option, value) config.set_and_save(option, value)
msg = "%s=%s" % (option, value) msg = "%s=%s" % (option, value)
room = self.current_room() room = self.current_room()
self.add_info(room, msg) self.add_message_to_room(room, msg)
# self.add_info(room, msg)
def command_show(self, args): def command_show(self, args):
""" """
@ -762,7 +807,8 @@ Avail: Sets your availability to available and (optional) sets your status
Displays an informational message in the "Info" room window Displays an informational message in the "Info" room window
""" """
room = self.get_room_by_name("Info") room = self.get_room_by_name("Info")
self.add_info(room, msg) self.add_message_to_room(room, msg)
# self.add_info(room, msg)
def command_quit(self, args): def command_quit(self, args):
""" """

View file

@ -21,61 +21,88 @@ from datetime import datetime
from random import randrange from random import randrange
from config import config from config import config
from logging import logger from logging import logger
from message import Message
class Room(object): class Room(object):
""" """
""" """
def __init__(self, name, nick, number): number = 0
def __init__(self, name, nick, window):
self.name = name self.name = name
self.own_nick = nick self.own_nick = nick
self.color_state = 11 # color used in RoomInfo self.color_state = 11 # color used in RoomInfo
self.nb = number # number used in RoomInfo self.nb = Room.number # number used in RoomInfo
Room.number += 1
self.joined = False # false until self presence is received self.joined = False # false until self presence is received
self.users = [] self.users = [] # User objects
self.lines = [] # (time, nick, msg) or (time, info) self.messages = [] # Message objects
self.topic = '' self.topic = ''
self.window = window
self.pos = 0 # offset
def scroll_up(self):
self.pos += 14
def scroll_down(self):
self.pos -= 14
if self.pos <= 0:
self.pos = 0
def disconnect(self): def disconnect(self):
self.joined = False self.joined = False
def add_message(self, nick, msg, date=None): def add_message(self, txt, time=None, nickname=None):
if not date: """
date = datetime.now() Note that user can be None even if nickname is not None. It happens
color = None when we receive an history message said by someone who is not
self.set_color_state(12) in the room anymore
if nick != self.own_nick and self.joined: # do the highlight thing """
if self.own_nick in msg: user = self.get_user_by_name(nickname) if nickname is not None else None
self.set_color_state(13) time = time if time is not None else datetime.now()
color = 3 from common import debug
else: # debug("add_message: %s, %s, %s, %s" % (str(txt), str(time), str(nickname), str(user)))
highlight_words = config.get('highlight_on', '').split(':') self.messages.append(Message(txt, time, nickname, user))
for word in highlight_words:
if word.lower() in msg.lower() and word != '':
self.set_color_state(13)
color = 3
break
if not msg:
logger.info('msg is None..., %s' % (nick))
return
self.lines.append((date, nick.encode('utf-8'),
msg.encode('utf-8'), color))
user = self.get_user_by_name(nick)
if user:
user.set_last_talked(date)
if self.joined: # log only NEW messages, not the history received on join
logger.message(self.name, nick.encode('utf-8'), msg.encode('utf-8'))
return color
def add_info(self, info, date=None): # def add_message(nick, msg, date=None)
""" info, like join/quit/status messages""" # TODO: limit the message kept in memory (configurable)
if not date:
date = datetime.now() # if not date:
try: # date = datetime.now()
self.lines.append((date, info.encode('utf-8'))) # color = None
return info.encode('utf-8') # self.set_color_state(12)
except: # if nick != self.own_nick and self.joined: # do the highlight thing
self.lines.append((date, info)) # if self.own_nick in msg:
return info # self.set_color_state(13)
# color = 3
# else:
# highlight_words = config.get('highlight_on', '').split(':')
# for word in highlight_words:
# if word.lower() in msg.lower() and word != '':
# self.set_color_state(13)
# color = 3
# break
# if not msg:
# logger.info('msg is None..., %s' % (nick))
# return
# self.lines.append((date, nick.encode('utf-8'),
# msg.encode('utf-8'), color))
# user = self.get_user_by_name(nick)
# if user:
# user.set_last_talked(date)
# if self.joined: # log only NEW messages, not the history received on join
# logger.message(self.name, nick.encode('utf-8'), msg.encode('utf-8'))
# return color
# def add_info(self, info, date=None):
# """ info, like join/quit/status messages"""
# if not date:
# date = datetime.now()
# try:
# self.lines.append((date, info.encode('utf-8')))
# return info.encode('utf-8')
# except:
# self.lines.append((date, info))
# return info
def get_user_by_name(self, nick): def get_user_by_name(self, nick):
for user in self.users: for user in self.users:

View file

@ -40,7 +40,9 @@ class Win(object):
# V_/_ # V_/_
print parent_win, parent_win.height, parent_win.width, height, width, y, x print parent_win, parent_win.height, parent_win.width, height, width, y, x
raise raise
self.win.idlok(1)
self.win.leaveok(1) self.win.leaveok(1)
self.win.syncok(0)
def refresh(self): def refresh(self):
self.win.noutrefresh() self.win.noutrefresh()
@ -50,7 +52,7 @@ class UserList(Win):
Win.__init__(self, height, width, y, x, parent_win) Win.__init__(self, height, width, y, x, parent_win)
self.visible = visible self.visible = visible
self.win.attron(curses.color_pair(2)) self.win.attron(curses.color_pair(2))
self.win.vline(0, 0, curses.ACS_VLINE, self.height) # self.win.vline(0, 0, curses.ACS_VLINE, self.height)
self.win.attroff(curses.color_pair(2)) self.win.attroff(curses.color_pair(2))
self.color_role = {'moderator': 3, self.color_role = {'moderator': 3,
'participant':2, 'participant':2,
@ -66,7 +68,7 @@ class UserList(Win):
def refresh(self, users): def refresh(self, users):
if not self.visible: if not self.visible:
return return
self.win.clear() self.win.erase()
y = 0 y = 0
for user in users: for user in users:
try: try:
@ -105,7 +107,7 @@ class Topic(Win):
def refresh(self, room_name): def refresh(self, room_name):
if not self.visible: if not self.visible:
return return
self.win.clear() self.win.erase()
try: try:
self.win.addnstr(0, 0, room_name + " "*(self.width-len(room_name)), self.width self.win.addnstr(0, 0, room_name + " "*(self.width-len(room_name)), self.width
, curses.color_pair(1)) , curses.color_pair(1))
@ -125,7 +127,7 @@ class RoomInfo(Win):
return return
def compare_room(a, b): def compare_room(a, b):
return a.nb - b.nb return a.nb - b.nb
self.win.clear() self.win.erase()
try: try:
self.win.addnstr(0, 0, current.name+" [", self.width self.win.addnstr(0, 0, current.name+" [", self.width
,curses.color_pair(1)) ,curses.color_pair(1))
@ -149,15 +151,21 @@ class RoomInfo(Win):
pass pass
self.win.refresh() self.win.refresh()
class TextWin(object): class TextWin(Win):
""" """
keep a dict of {winname: window} # keep a dict of {winname: window}
when a new message is received in a room, just add # when a new message is received in a room, just add
the line at the bottom (and scroll if needed) # the line at the bottom (and scroll if needed)
when the current room is changed, just refresh the # when the current room is changed, just refresh the
associated window # associated window
When the term is resized, rebuild ALL the windows # When the term is resized, rebuild ALL the windows
(the complete lines lists are keeped in the Room class) # (the complete lines lists are keeped in the Room class)
Nope, don't do that anymore.
Weechat is doing it the easy way, and it's working, there's no
reason poezio can't do it (it's python, but that shouldn't change
anything)
Just keep ONE single window for the text area and rewrite EVERYTHING
on each change.
""" """
def __init__(self, height, width, y, x, parent_win, visible): def __init__(self, height, width, y, x, parent_win, visible):
self.visible = visible self.visible = visible
@ -166,79 +174,156 @@ class TextWin(object):
self.y = y self.y = y
self.x = x self.x = x
self.parent_win = parent_win self.parent_win = parent_win
self.wins = {} Win.__init__(self, height, width, y, x, parent_win)
def redraw(self, room): def refresh(self, room):
""" """
called when the buffer changes or is
resized (a complete redraw is needed)
""" """
if not self.visible: # TODO: keep a position in the room, and display
return # the messages from this position (can be used to scroll)
win = self.wins[room.name].win from common import debug
win.clear() y = 0
win.move(0, 0) self.win.erase()
for line in room.lines: if room.pos != 0:
self.add_line(room, line) messages = room.messages[-self.height - room.pos : -room.pos]
else:
messages = room.messages[-self.height:]
for message in messages:
# debug(str(message))
self.write_time(y, message.time)
if message.nickname is not None:
x = self.write_nickname(y, message.nickname.encode('utf-8'), message.user)
else:
x = 11
self.win.attron(curses.color_pair(8))
y += self.write_text(y, x, message.txt)
if message.nickname is None:
self.win.attroff(curses.color_pair(8))
# self.win.addnstr(y, x, message.txt, 40)
# self.win
y += 1
self.win.refresh()
def refresh(self, winname): def write_text(self, y, x, txt):
if self.visible: """
self.wins[winname].refresh() return the number of line written, -1
"""
txt = txt.encode('utf-8')
l = 0
while txt != '':
debug(txt)
if txt[:self.width-x].find('\n') != -1:
limit = txt[:self.width-x].find('\n')
debug("=================="+str(limit))
else:
limit = self.width-x
self.win.addnstr(y+l, x, txt, limit)
txt = txt[limit+1:]
l += 1
return l-1
def add_line(self, room, line): def write_nickname(self, y, nickname, user):
if not self.visible: """
return Write the nickname, using the user's color
win = self.wins[room.name].win and return the number of written characters
users = room.users """
win.addstr('\n['+line[0].strftime("%H")) if user:
win.attron(curses.color_pair(9)) self.win.attron(curses.color_pair(user.color))
win.addstr(':') self.win.addstr(y, 11, nickname)
win.attroff(curses.color_pair(9)) if user:
win.addstr(line[0].strftime('%M')) self.win.attroff(curses.color_pair(user.color))
win.attron(curses.color_pair(9)) self.win.addnstr(y, 11+len(nickname.decode('utf-8')), "> ", 2)
win.addstr(':') return len(nickname.decode('utf-8')) + 13
win.attroff(curses.color_pair(9))
win.addstr(line[0].strftime('%S') + "] ")
if len(line) == 2:
try:
win.attron(curses.color_pair(8))
win.addstr(line[1])
win.attroff(curses.color_pair(8))
except:pass
elif len(line) == 4:
for user in users:
if user.nick == line[1]:
break
try:
length = len('['+line[0].strftime("%H:%M:%S") + "] <")
if line[1]:
win.attron(curses.color_pair(user.color))
win.addstr(line[1])
win.attroff(curses.color_pair(user.color))
win.addstr("> ")
if line[3]:
win.attron(curses.color_pair(line[3]))
win.addstr(line[2])
if line[3]:
win.attroff(curses.color_pair(line[3]))
except:pass
def new_win(self, winname): def write_time(self, y, time):
newwin = Win(self.height, self.width, self.y, self.x, self.parent_win) """
newwin.win.idlok(True) Write the date on the yth line of the window
newwin.win.scrollok(True) """
newwin.win.leaveok(1) self.win.addnstr(y, 0, '['+time.strftime("%H"), 3)
self.wins[winname] = newwin self.win.attron(curses.color_pair(9))
self.win.addnstr(y, 3, ':', 1)
self.win.attroff(curses.color_pair(9))
self.win.addstr(y, 4, time.strftime('%M'), 2)
self.win.attron(curses.color_pair(9))
self.win.addstr(y, 6, ':', 1)
self.win.attroff(curses.color_pair(9))
self.win.addstr(y, 7, time.strftime('%S') + "] ", 3)
def resize(self, height, width, y, x, stdscr, visible): def resize(self, height, width, y, x, stdscr, visible):
self.visible = visible self._resize(height, width, y, x, stdscr)
if not visible:
return # def redraw(self, room):
for winname in self.wins.keys(): # """
self.wins[winname]._resize(height, width, y, x, stdscr) # called when the buffer changes or is
self.wins[winname].win.idlok(True) # resized (a complete redraw is needed)
self.wins[winname].win.scrollok(True) # """
self.wins[winname].win.leaveok(1) # if not self.visible:
# return
# win = self.wins[room.name].win
# win.clear()
# win.move(0, 0)
# for line in room.lines:
# self.add_line(room, line)
# def refresh(self, winname):
# self.
# if self.visible:
# self.wins[winname].refresh()
# def add_line(self, room, line):
# if not self.visible:
# return
# win = self.wins[room.name].win
# users = room.users
# win.addstr('\n['+line[0].strftime("%H"))
# win.attron(curses.color_pair(9))
# win.addstr(':')
# win.attroff(curses.color_pair(9))
# win.addstr(line[0].strftime('%M'))
# win.attron(curses.color_pair(9))
# win.addstr(':')
# win.attroff(curses.color_pair(9))
# win.addstr(line[0].strftime('%S') + "] ")
# if len(line) == 2:
# try:
# win.attron(curses.color_pair(8))
# win.addstr(line[1])
# win.attroff(curses.color_pair(8))
# except:pass
# elif len(line) == 4:
# for user in users:
# if user.nick == line[1]:
# break
# try:
# length = len('['+line[0].strftime("%H:%M:%S") + "] <")
# if line[1]:
# win.attron(curses.color_pair(user.color))
# win.addstr(line[1])
# win.attroff(curses.color_pair(user.color))
# win.addstr("> ")
# if line[3]:
# win.attron(curses.color_pair(line[3]))
# win.addstr(line[2])
# if line[3]:
# win.attroff(curses.color_pair(line[3]))
# except:pass
# def new_win(self, winname):
# newwin = Win(self.height, self.width, self.y, self.x, self.parent_win)
# newwin.win.idlok(True)
# newwin.win.scrollok(True)
# newwin.win.leaveok(1)
# self.wins[winname] = newwin
# def resize(self, height, width, y, x, stdscr, visible):
# self.visible = visible
# if not visible:
# return
# for winname in self.wins.keys():
# self.wins[winname]._resize(height, width, y, x, stdscr)
# self.wins[winname].win.idlok(True)
# self.wins[winname].win.scrollok(True)
# self.wins[winname].win.leaveok(1)
class Input(Win): class Input(Win):
""" """
@ -483,10 +568,10 @@ class Input(Win):
def refresh(self): def refresh(self):
if not self.visible: if not self.visible:
return return
self.win.noutrefresh() self.win.refresh()
def clear_text(self): def clear_text(self):
self.win.clear() self.win.erase()
class Window(object): class Window(object):
""" """
@ -542,8 +627,8 @@ class Window(object):
'room' is the current one 'room' is the current one
""" """
room = rooms[0] # get current room room = rooms[0] # get current room
self.text_win.redraw(room) # self.text_win.redraw(room)
self.text_win.refresh(room.name) self.text_win.refresh(room)
self.user_win.refresh(room.users) self.user_win.refresh(room.users)
self.topic_win.refresh(room.topic) self.topic_win.refresh(room.topic)
self.info_win.refresh(rooms, room) self.info_win.refresh(rooms, room)
@ -553,5 +638,5 @@ class Window(object):
self.input.do_command(key) self.input.do_command(key)
self.input.refresh() self.input.refresh()
def new_room(self, room): # def new_room(self, room):
self.text_win.new_win(room.name) # self.text_win.new_win(room.name)