Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import tinychat
- import curses
- import thread
- import sys
- # Tinychat client by MegaLoler
- rooms = []
- activeRoom = None
- generalBuffer = []
- contents = ["", "", ""]
- focus = 1
- screen = curses.initscr()
- curses.noecho()
- curses.start_color()
- HELP_MSG = "Press TAB to switch between the three text feilds at the bottom. Type in room names on the left to connect to rooms. Once connected, type in messages in the middle. Type in private messages on the right. To toggle between open rooms press \"`\". To toggle between private message recipients press \"~\". The selected recipient will be highlighted in red. Type /commands in the middle when connected to a room to get a list of commands that you can use. Press ESC twice to exit the client."
- size = screen.getmaxyx()
- WIDTH = size[1]
- HEIGHT = size[0]
- HALF = WIDTH / 2
- QUARTER = WIDTH / 4
- RED = 1
- YELLOW = 2
- GREEN = 3
- CYAN = 4
- BLUE = 5
- MAGENTA = 6
- NORMAL = 7
- curses.init_pair(RED, curses.COLOR_RED, curses.COLOR_BLACK)
- curses.init_pair(YELLOW, curses.COLOR_YELLOW, curses.COLOR_BLACK)
- curses.init_pair(GREEN, curses.COLOR_GREEN, curses.COLOR_BLACK)
- curses.init_pair(CYAN, curses.COLOR_CYAN, curses.COLOR_BLACK)
- curses.init_pair(BLUE, curses.COLOR_BLUE, curses.COLOR_BLACK)
- curses.init_pair(MAGENTA, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
- curses.init_pair(NORMAL, curses.COLOR_WHITE, curses.COLOR_BLACK)
- def printLine(string, color=NORMAL):
- generalBuffer.append((string, color))
- while len(generalBuffer) > HEIGHT - 3: del generalBuffer[0]
- def addMessage(string, color=NORMAL):
- for string in string.split("\n"):
- buf = ""
- for i in string:
- buf += i
- if len(buf) >= HALF:
- printLine(buf, color)
- buf = ""
- if buf != "": printLine(buf, color)
- if activeRoom == None:
- drawChat()
- screen.refresh()
- def hexToDec(h):
- h = h.lower()
- if h == "f":
- return 15
- elif h == "e":
- return 14
- elif h == "d":
- return 13
- elif h == "c":
- return 12
- elif h == "b":
- return 11
- elif h == "a":
- return 10
- else:
- try:
- return int(h)
- except:
- return 0
- def hexToAnsi(col):
- if col[0] == "#": col = col[1:]
- if len(col) == 3:
- r = hexToDec(col[0])
- g = hexToDec(col[1])
- b = hexToDec(col[2])
- elif len(col) == 6:
- r = hexToDec(col[0])
- g = hexToDec(col[2])
- b = hexToDec(col[4])
- else:
- return NORMAL
- r = r > 3
- g = g > 3
- b = b > 3
- if r and g and b:
- return NORMAL
- if r and g:
- return YELLOW
- if g and b:
- return CYAN
- if r and b:
- return MAGENTA
- if r:
- return RED
- if g:
- return GREEN
- if b:
- return BLUE
- else:
- return NORMAL
- class TinychatRoom(tinychat.TinychatRoom):
- def printLine(self, string, color=NORMAL):
- self.chatBuffer.append((string, color))
- while len(self.chatBuffer) > HEIGHT - 3: del self.chatBuffer[0]
- def addMessage(self, string, color=NORMAL):
- for string in string.split("\n"):
- buf = ""
- for i in string:
- buf += i
- if len(buf) >= HALF:
- self.printLine(buf, color)
- buf = ""
- if buf != "": self.printLine(buf, color)
- if activeRoom == self:
- drawChat()
- screen.refresh()
- else:
- self.new = True
- drawRooms()
- screen.refresh()
- def onMessage(self, user, message):
- self.addMessage(user.nick + ": " + message.msg, hexToAnsi(message.color))
- def onPM(self, user, message):
- self.addMessage("@" + self.nick + ": " + user.nick + ": " + message.msg, hexToAnsi(message.color))
- def onQuit(self, user):
- self.addMessage(user.nick + " left the room.")
- drawOnline()
- screen.refresh()
- def onJoin(self, user):
- self.addMessage(user.nick + " entered the room.")
- drawOnline()
- screen.refresh()
- def onRegister(self, user):
- self.addMessage("You have connected to " + self.room + ".")
- def onNickChange(self, new, old, user):
- self.addMessage(old + " changed nickname to " + new + ".")
- drawOnline()
- screen.refresh()
- def onUserList(self, users):
- drawOnline()
- screen.refresh()
- def onTopic(self, topic):
- self.addMessage("Topic set to \"" + topic + "\"")
- drawHeaders()
- def centerString(string, length):
- off = length - len(string)
- if off > 0:
- l = off / 2
- if off % 2:
- r = l + 1
- else:
- r = l
- return " " * l + string + " " * r
- elif off < 0:
- return string[:length]
- def leftString(string, length):
- if len(string) > length:
- return string[:length]
- else:
- off = length - len(string)
- return string + " " * off
- def rightString(string, length):
- if len(string) > length:
- return string[:length]
- else:
- off = length - len(string)
- return string + off * " "
- def fieldString(string, length):
- if len(string) > length:
- return string[-length:]
- else:
- off = length - len(string)
- return string + off * " "
- def fieldLength(string, length):
- if len(string) > length:
- return length
- else:
- return len(string)
- def drawRooms():
- y = 0
- for y in range(len(rooms)):
- if y >= HEIGHT - 2: break
- room = rooms[y]
- if room.new:
- attr = curses.color_pair(YELLOW) | curses.A_BOLD
- else:
- attr = curses.color_pair(NORMAL)
- if room == activeRoom: attr |= curses.A_REVERSE
- screen.addstr(y + 1, 0, leftString(room.room, QUARTER), attr)
- if len(rooms) > 0: y += 1
- while y < HEIGHT - 2:
- screen.addstr(y + 1, 0, leftString("", QUARTER), curses.color_pair(NORMAL))
- y += 1
- def drawOnline():
- if not activeRoom:
- users = []
- else:
- users = sorted(activeRoom.users.items())
- y = 0
- for y in range(len(users)):
- if y >= HEIGHT - 2: break
- nick = users[y][1].nick
- if activeRoom and activeRoom.activeUser == users[y][1]:
- attr = curses.color_pair(RED) | curses.A_REVERSE
- else:
- attr = curses.color_pair(NORMAL)
- if nick == activeRoom.nick: attr |= curses.A_REVERSE
- screen.addstr(y + 1, HALF + QUARTER, rightString(nick, QUARTER), attr)
- if len(users) > 0: y += 1
- while y < HEIGHT - 2:
- screen.addstr(y + 1, HALF + QUARTER, rightString("", QUARTER), curses.color_pair(NORMAL))
- y += 1
- def drawChat():
- if not activeRoom:
- chatBuffer = generalBuffer
- else:
- chatBuffer = activeRoom.chatBuffer
- y = 0
- for y in range(len(chatBuffer)):
- if y >= HEIGHT - 3: break
- message = chatBuffer[y]
- screen.addstr(y + 1, QUARTER, leftString(message[0], HALF), curses.color_pair(message[1]))
- if len(chatBuffer) > 0: y += 1
- while y < HEIGHT - 3:
- screen.addstr(y + 1, QUARTER, leftString("", HALF), curses.color_pair(NORMAL))
- y += 1
- def drawField(y, x, content, width, selected, color=NORMAL):
- attr = curses.color_pair(color)
- if selected: attr |= curses.A_REVERSE
- screen.addstr(y, x, fieldString(content, width), attr)
- if selected:
- return (y, x + fieldLength(content, width))
- else:
- return None
- def drawFields():
- if activeRoom:
- color = hexToAnsi(activeRoom.color)
- else:
- color = NORMAL
- f1 = drawField(HEIGHT - 1, 0, contents[0], QUARTER - 1, focus == 0)
- f2 = drawField(HEIGHT - 1, QUARTER, contents[1], HALF - 1, focus == 1, color)
- f3 = drawField(HEIGHT - 1, HALF + QUARTER, contents[2], QUARTER - 1, focus == 2, color)
- if f1:
- screen.move(f1[0], f1[1])
- elif f2:
- screen.move(f2[0], f2[1])
- elif f3:
- screen.move(f3[0], f3[1])
- def drawHeaders():
- if activeRoom and activeRoom.topic:
- header = "TOPIC: " + activeRoom.topic
- else:
- header = "TINYCHAT"
- screen.addstr(0, 0, centerString("ROOMS", QUARTER), curses.color_pair(NORMAL) | curses.A_REVERSE)
- screen.addstr(0, QUARTER, centerString(header, HALF), curses.color_pair(NORMAL) | curses.A_REVERSE)
- screen.addstr(0, HALF + QUARTER, centerString("ONLINE", QUARTER), curses.color_pair(NORMAL) | curses.A_REVERSE)
- def drawContent():
- drawRooms()
- drawOnline()
- drawChat()
- def drawInterface():
- drawHeaders()
- drawContent()
- drawFields()
- screen.refresh()
- def alreadyConnected(room):
- for i in rooms:
- if i.room.lower() == room.lower(): return i
- return None
- def switchRoom(room):
- global activeRoom
- activeRoom = room
- room.new = False
- drawContent()
- drawHeaders()
- screen.border(0)
- prompt = "Enter your username: "
- screen.addstr(HEIGHT / 2, HALF - len(prompt), prompt)
- screen.refresh()
- NICK = ""
- while True:
- c = screen.getch()
- if c == 10 and NICK != "":
- NICK = NICK.strip()
- break
- elif c == 127:
- if NICK != "": NICK = NICK[:-1]
- screen.addstr(HEIGHT / 2, HALF, leftString(NICK, HALF))
- screen.border(0)
- screen.move(HEIGHT / 2, HALF + len(NICK))
- screen.refresh()
- elif c == 27:
- curses.endwin()
- sys.exit()
- else:
- if len(NICK) < HALF - 1:
- NICK += chr(c)
- screen.addstr(HEIGHT / 2, HALF, leftString(NICK, HALF))
- screen.border(0)
- screen.move(HEIGHT / 2, HALF + len(NICK))
- screen.refresh()
- screen.erase()
- drawInterface()
- addMessage("Welcome to MegaLoler's Tinychat Client!\nJoin a room to get started.")
- #todo
- #moderator commands
- #deal with nonexistant rooms
- #add command history with up arrow
- #disconnection error handling and stuff
- #dynamic sizing
- esc = False
- while True:
- drawFields() #perhaps make more effient later
- c = screen.getch()
- if c == 10: # Enter
- msg = contents[focus].strip()
- if msg != "":
- contents[focus] = ""
- if focus == 0:
- r = alreadyConnected(msg)
- if r == None:
- room = TinychatRoom(msg, NICK)
- thread.start_new_thread(room.connect, ())
- room.chatBuffer = []
- room.activeUser = None
- room.new = False
- rooms.append(room)
- switchRoom(room)
- else:
- switchRoom(r)
- elif focus == 1:
- if activeRoom:
- if msg[0] == "/":
- msg = msg[1:]
- if msg != "":
- parts = msg.split(" ")
- cmd = parts[0].lower()
- if len(parts) == 1:
- pars = []
- else:
- pars = parts[1:]
- par = " ".join(pars)
- if cmd == "color":
- activeRoom.cycleColor()
- drawChat()
- elif cmd == "nick":
- activeRoom.setNick(par)
- drawOnline()
- elif cmd == "help":
- activeRoom.addMessage(HELP_MSG)
- elif cmd == "part":
- for i in range(len(rooms)):
- if rooms[i] == activeRoom: break
- rooms.remove(activeRoom)
- activeRoom.disconnect()
- if len(rooms) > 0:
- i %= len(rooms)
- switchRoom(rooms[i])
- else:
- activeRoom = None
- drawContent()
- else:
- activeRoom.addMessage("Commands: /color (cycles through a list of possible colors), /nick [nick] (allows you to change your nick), /part (disconnect from the current room), /help (get help on how to use this client)")
- else:
- activeRoom.say(msg)
- activeRoom.addMessage(activeRoom.nick + ": " + msg, hexToAnsi(activeRoom.color))
- else:
- if msg == "/help":
- addMessage(HELP_MSG)
- else:
- addMessage("You are not connected to any rooms! Type /help for help.")
- elif focus == 2:
- if activeRoom and activeRoom.activeUser:
- activeRoom.pm(msg, activeRoom.activeUser.nick)
- activeRoom.addMessage("@" + activeRoom.activeUser.nick + ": " + activeRoom.nick + ": " + msg, hexToAnsi(activeRoom.color))
- drawFields()
- screen.refresh()
- elif c == 9: # Tab
- focus = (focus + 1) % 3
- drawFields()
- screen.refresh()
- elif c == 96: # `
- if len(rooms) > 0:
- for i in range(len(rooms)):
- if rooms[i] == activeRoom: break
- i = (i + 1) % len(rooms)
- switchRoom(rooms[i])
- elif c == 126: # ~
- if activeRoom:
- if len(activeRoom.users) > 0:
- users = sorted(activeRoom.users.items())
- for i in range(len(users)):
- if users[i][1] == activeRoom.activeUser: break
- i = (i + 1) % (len(activeRoom.users))
- activeRoom.activeUser = users[i][1]
- drawOnline()
- elif c == 127: # Backspace
- if contents[focus] != "": contents[focus] = contents[focus][:-1]
- drawFields()
- screen.refresh()
- elif c == 27: # Esc
- if esc:
- break
- else:
- esc = True
- continue
- else:
- contents[focus] += chr(c)
- drawFields()
- screen.refresh()
- esc = False
- curses.endwin()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement