fdfdas
This commit is contained in:
parent
4b965814b9
commit
79e4de5710
26 changed files with 1269 additions and 699 deletions
5
TODO
5
TODO
|
@ -1,5 +1,7 @@
|
|||
Features:
|
||||
* Chat rooms/browser
|
||||
* PESTERLOG: in convo window
|
||||
* help button on quirks menu?
|
||||
* tab recombining gives wrong window icon
|
||||
* help menu -- about and forum
|
||||
* profile switch should say current profile
|
||||
|
@ -13,6 +15,7 @@ Features:
|
|||
* tab right-click menu on tabbed convos
|
||||
* comment history (up button)
|
||||
* page up/down scrolling
|
||||
* get rid of border on chat window?
|
||||
* ctrl-tab should prefer new convos
|
||||
* More complex quirks: random, spelling, by-sound
|
||||
* Implement TC options
|
||||
|
@ -28,7 +31,7 @@ Features:
|
|||
* Theme checking
|
||||
* don't clear new message when clicking away from tab?
|
||||
* Spy mode
|
||||
|
||||
* Animated
|
||||
* put code into separate files
|
||||
* hide offline chums
|
||||
* chum list groups
|
||||
|
|
438
convo.py
Normal file
438
convo.py
Normal file
|
@ -0,0 +1,438 @@
|
|||
from string import Template
|
||||
import re
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
from dataobjs import PesterProfile, Mood
|
||||
from generic import PesterIcon
|
||||
from parsetools import escapeBrackets, convertTags
|
||||
|
||||
class PesterTabWindow(QtGui.QFrame):
|
||||
def __init__(self, mainwindow, parent=None):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
self.setFocusPolicy(QtCore.Qt.ClickFocus)
|
||||
self.mainwindow = mainwindow
|
||||
self.resize(*self.mainwindow.theme["convo/size"])
|
||||
self.setStyleSheet(self.mainwindow.theme["convo/style"])
|
||||
|
||||
self.tabs = QtGui.QTabBar(self)
|
||||
self.tabs.setTabsClosable(True)
|
||||
self.connect(self.tabs, QtCore.SIGNAL('currentChanged(int)'),
|
||||
self, QtCore.SLOT('changeTab(int)'))
|
||||
self.connect(self.tabs, QtCore.SIGNAL('tabCloseRequested(int)'),
|
||||
self, QtCore.SLOT('tabClose(int)'))
|
||||
self.tabs.setShape(self.mainwindow.theme["convo/tabs/tabstyle"])
|
||||
self.tabs.setStyleSheet("QTabBar::tab{ %s } QTabBar::tab:selected { %s }" % (self.mainwindow.theme["convo/tabs/style"], self.mainwindow.theme["convo/tabs/selectedstyle"]))
|
||||
|
||||
self.layout = QtGui.QVBoxLayout()
|
||||
self.layout.setContentsMargins(0,0,0,0)
|
||||
self.layout.addWidget(self.tabs)
|
||||
self.setLayout(self.layout)
|
||||
self.convos = {}
|
||||
self.tabIndices = {}
|
||||
self.currentConvo = None
|
||||
self.changedTab = False
|
||||
self.softclose = False
|
||||
|
||||
# get default tab color i guess
|
||||
self.defaultTabTextColor = self.getTabTextColor()
|
||||
def getTabTextColor(self):
|
||||
# ugly, ugly hack
|
||||
self.changedTab = True
|
||||
i = self.tabs.addTab(".")
|
||||
c = self.tabs.tabTextColor(i)
|
||||
self.tabs.removeTab(i)
|
||||
self.changedTab = False
|
||||
return c
|
||||
def addChat(self, convo):
|
||||
self.convos[convo.chum.handle] = convo
|
||||
# either addTab or setCurrentIndex will trigger changed()
|
||||
newindex = self.tabs.addTab(convo.chum.handle)
|
||||
self.tabIndices[convo.chum.handle] = newindex
|
||||
self.tabs.setCurrentIndex(newindex)
|
||||
self.tabs.setTabIcon(newindex, convo.chum.mood.icon(self.mainwindow.theme))
|
||||
def showChat(self, handle):
|
||||
tabi = self.tabIndices[handle]
|
||||
if self.tabs.currentIndex() == tabi:
|
||||
self.activateWindow()
|
||||
self.raise_()
|
||||
self.convos[handle].raiseChat()
|
||||
else:
|
||||
self.tabs.setCurrentIndex(tabi)
|
||||
|
||||
def convoHasFocus(self, convo):
|
||||
if ((self.hasFocus() or self.tabs.hasFocus()) and
|
||||
self.tabs.tabText(self.tabs.currentIndex()) == convo.chum.handle):
|
||||
return True
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
keypress = event.key()
|
||||
mods = event.modifiers()
|
||||
if ((mods & QtCore.Qt.ControlModifier) and
|
||||
keypress == QtCore.Qt.Key_Tab):
|
||||
nexti = (self.tabIndices[self.currentConvo.chum.handle] + 1) % self.tabs.count()
|
||||
self.tabs.setCurrentIndex(nexti)
|
||||
|
||||
def closeSoft(self):
|
||||
self.softclose = True
|
||||
self.close()
|
||||
def updateBlocked(self, handle):
|
||||
i = self.tabIndices[handle]
|
||||
icon = QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"])
|
||||
self.tabs.setTabIcon(i, icon)
|
||||
if self.tabs.currentIndex() == i:
|
||||
self.setWindowIcon(icon)
|
||||
def updateMood(self, handle, mood, unblocked=False):
|
||||
i = self.tabIndices[handle]
|
||||
if handle in self.mainwindow.config.getBlocklist() and not unblocked:
|
||||
icon = QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"])
|
||||
else:
|
||||
icon = mood.icon(self.mainwindow.theme)
|
||||
self.tabs.setTabIcon(i, icon)
|
||||
if self.tabs.currentIndex() == i:
|
||||
self.setWindowIcon(icon)
|
||||
def closeEvent(self, event):
|
||||
if not self.softclose:
|
||||
while self.tabs.count() > 0:
|
||||
self.tabClose(0)
|
||||
self.windowClosed.emit()
|
||||
def focusInEvent(self, event):
|
||||
# make sure we're not switching tabs!
|
||||
i = self.tabs.tabAt(self.mapFromGlobal(QtGui.QCursor.pos()))
|
||||
if i == -1:
|
||||
i = self.tabs.currentIndex()
|
||||
handle = unicode(self.tabs.tabText(i))
|
||||
self.clearNewMessage(handle)
|
||||
def convoHasFocus(self, handle):
|
||||
i = self.tabIndices[handle]
|
||||
if (self.tabs.currentIndex() == i and
|
||||
(self.hasFocus() or self.tabs.hasFocus())):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def notifyNewMessage(self, handle):
|
||||
i = self.tabIndices[handle]
|
||||
self.tabs.setTabTextColor(i, QtGui.QColor(self.mainwindow.theme["convo/tabs/newmsgcolor"]))
|
||||
convo = self.convos[handle]
|
||||
def func():
|
||||
convo.showChat()
|
||||
self.mainwindow.waitingMessages.addMessage(handle, func)
|
||||
# set system tray
|
||||
def clearNewMessage(self, handle):
|
||||
try:
|
||||
i = self.tabIndices[handle]
|
||||
self.tabs.setTabTextColor(i, self.defaultTabTextColor)
|
||||
except KeyError:
|
||||
pass
|
||||
self.mainwindow.waitingMessages.messageAnswered(handle)
|
||||
def changeTheme(self, theme):
|
||||
self.resize(*theme["convo/size"])
|
||||
self.setStyleSheet(theme["convo/style"])
|
||||
self.tabs.setShape(theme["convo/tabs/tabstyle"])
|
||||
self.tabs.setStyleSheet("QTabBar::tabs{ %s }" % (theme["convo/tabs/style"]))
|
||||
for c in self.convos.values():
|
||||
tabi = self.tabIndices[c.chum.handle]
|
||||
self.tabs.setTabIcon(tabi, c.chum.mood.icon(theme))
|
||||
currenttabi = self.tabs.currentIndex()
|
||||
if currenttabi >= 0:
|
||||
currentHandle = unicode(self.tabs.tabText(self.tabs.currentIndex()))
|
||||
self.setWindowIcon(self.convos[currentHandle].chum.mood.icon(theme))
|
||||
self.defaultTabTextColor = self.getTabTextColor()
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def tabClose(self, i):
|
||||
handle = unicode(self.tabs.tabText(i))
|
||||
self.mainwindow.waitingMessages.messageAnswered(handle)
|
||||
convo = self.convos[handle]
|
||||
del self.convos[handle]
|
||||
del self.tabIndices[handle]
|
||||
self.tabs.removeTab(i)
|
||||
for (h, j) in self.tabIndices.iteritems():
|
||||
if j > i:
|
||||
self.tabIndices[h] = j-1
|
||||
self.layout.removeWidget(convo)
|
||||
convo.close()
|
||||
if self.tabs.count() == 0:
|
||||
self.close()
|
||||
return
|
||||
if self.currentConvo == convo:
|
||||
currenti = self.tabs.currentIndex()
|
||||
currenth = unicode(self.tabs.tabText(currenti))
|
||||
self.currentConvo = self.convos[currenth]
|
||||
self.currentConvo.raiseChat()
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def changeTab(self, i):
|
||||
if i < 0:
|
||||
return
|
||||
if self.changedTab:
|
||||
self.changedTab = False
|
||||
return
|
||||
handle = unicode(self.tabs.tabText(i))
|
||||
convo = self.convos[handle]
|
||||
if self.currentConvo:
|
||||
self.layout.removeWidget(self.currentConvo)
|
||||
self.currentConvo = convo
|
||||
self.layout.addWidget(convo)
|
||||
self.setWindowIcon(convo.chum.mood.icon(self.mainwindow.theme))
|
||||
self.setWindowTitle(convo.chum.handle)
|
||||
self.activateWindow()
|
||||
self.raise_()
|
||||
convo.raiseChat()
|
||||
|
||||
windowClosed = QtCore.pyqtSignal()
|
||||
|
||||
class PesterText(QtGui.QTextEdit):
|
||||
def __init__(self, theme, parent=None):
|
||||
QtGui.QTextEdit.__init__(self, parent)
|
||||
self.setStyleSheet(theme["convo/textarea/style"])
|
||||
self.setReadOnly(True)
|
||||
self.setMouseTracking(True)
|
||||
def addMessage(self, text, chum):
|
||||
color = chum.colorhtml()
|
||||
systemColor = QtGui.QColor(self.parent().mainwindow.theme["convo/systemMsgColor"])
|
||||
initials = chum.initials()
|
||||
msg = unicode(text)
|
||||
parent = self.parent()
|
||||
window = parent.mainwindow
|
||||
me = window.profile()
|
||||
if msg == "PESTERCHUM:BEGIN":
|
||||
parent.setChumOpen(True)
|
||||
msg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"])
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
elif msg == "PESTERCHUM:CEASE":
|
||||
parent.setChumOpen(False)
|
||||
msg = chum.pestermsg(me, systemColor, window.theme["convo/text/ceasepester"])
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
elif msg == "PESTERCHUM:BLOCK":
|
||||
msg = chum.pestermsg(me, systemColor, window.theme['convo/text/blocked'])
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
elif msg == "PESTERCHUM:UNBLOCK":
|
||||
msg = chum.pestermsg(me, systemColor, window.theme['convo/text/unblocked'])
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
elif msg[0:3] == "/me" or msg[0:13] == "PESTERCHUM:ME":
|
||||
if msg[0:3] == "/me":
|
||||
start = 3
|
||||
else:
|
||||
start = 13
|
||||
space = msg.find(" ")
|
||||
msg = chum.memsg(systemColor, msg[start:space], msg[space:])
|
||||
if chum is me:
|
||||
window.chatlog.log(parent.chum.handle, convertTags(msg, "bbcode"))
|
||||
else:
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
else:
|
||||
if not parent.chumopen and chum is not me:
|
||||
beginmsg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"])
|
||||
parent.setChumOpen(True)
|
||||
window.chatlog.log(chum.handle, convertTags(beginmsg, "bbcode"))
|
||||
self.append(convertTags(beginmsg))
|
||||
|
||||
msg = "<c=%s>%s: %s</c>" % (color, initials, msg)
|
||||
msg = escapeBrackets(msg)
|
||||
self.append(convertTags(msg))
|
||||
if chum is me:
|
||||
window.chatlog.log(parent.chum.handle, convertTags(msg, "bbcode"))
|
||||
else:
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
def changeTheme(self, theme):
|
||||
self.setStyleSheet(theme["convo/textarea/style"])
|
||||
sb = self.verticalScrollBar()
|
||||
sb.setMaximum(sb.maximum()+1000) # ugly hack but whatcha gonna do
|
||||
sb.setValue(sb.maximum())
|
||||
def focusInEvent(self, event):
|
||||
self.parent().clearNewMessage()
|
||||
QtGui.QTextEdit.focusInEvent(self, event)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
url = self.anchorAt(event.pos())
|
||||
if url != "":
|
||||
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode))
|
||||
QtGui.QTextEdit.mousePressEvent(self, event)
|
||||
def mouseMoveEvent(self, event):
|
||||
QtGui.QTextEdit.mouseMoveEvent(self, event)
|
||||
if self.anchorAt(event.pos()):
|
||||
if self.viewport().cursor().shape != QtCore.Qt.PointingHandCursor:
|
||||
self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
|
||||
else:
|
||||
self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.IBeamCursor))
|
||||
|
||||
class PesterInput(QtGui.QLineEdit):
|
||||
def __init__(self, theme, parent=None):
|
||||
QtGui.QLineEdit.__init__(self, parent)
|
||||
self.setStyleSheet(theme["convo/input/style"])
|
||||
def changeTheme(self, theme):
|
||||
self.setStyleSheet(theme["convo/input/style"])
|
||||
def focusInEvent(self, event):
|
||||
self.parent().clearNewMessage()
|
||||
QtGui.QLineEdit.focusInEvent(self, event)
|
||||
|
||||
class PesterConvo(QtGui.QFrame):
|
||||
def __init__(self, chum, initiated, mainwindow, parent=None):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
self.setFocusPolicy(QtCore.Qt.ClickFocus)
|
||||
self.chum = chum
|
||||
self.mainwindow = mainwindow
|
||||
convo = self.mainwindow.theme["convo"]
|
||||
self.resize(*convo["size"])
|
||||
self.setStyleSheet(convo["style"])
|
||||
self.setWindowIcon(chum.mood.icon(self.mainwindow.theme))
|
||||
self.setWindowTitle(chum.handle)
|
||||
|
||||
t = Template(self.mainwindow.theme["convo/chumlabel/text"])
|
||||
|
||||
self.chumLabel = QtGui.QLabel(t.safe_substitute(handle=chum.handle), self)
|
||||
self.chumLabel.setStyleSheet(self.mainwindow.theme["convo/chumlabel/style"])
|
||||
self.chumLabel.setAlignment(self.aligndict["h"][self.mainwindow.theme["convo/chumlabel/align/h"]] | self.aligndict["v"][self.mainwindow.theme["convo/chumlabel/align/v"]])
|
||||
self.chumLabel.setMaximumHeight(self.mainwindow.theme["convo/chumlabel/maxheight"])
|
||||
self.chumLabel.setMinimumHeight(self.mainwindow.theme["convo/chumlabel/minheight"])
|
||||
self.chumLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding))
|
||||
self.textArea = PesterText(self.mainwindow.theme, self)
|
||||
self.textInput = PesterInput(self.mainwindow.theme, self)
|
||||
self.textInput.setFocus()
|
||||
|
||||
self.connect(self.textInput, QtCore.SIGNAL('returnPressed()'),
|
||||
self, QtCore.SLOT('sentMessage()'))
|
||||
|
||||
self.layout = QtGui.QVBoxLayout()
|
||||
self.layout.addWidget(self.chumLabel)
|
||||
self.layout.addWidget(self.textArea)
|
||||
self.layout.addWidget(self.textInput)
|
||||
self.layout.setSpacing(0)
|
||||
margins = self.mainwindow.theme["convo/margins"]
|
||||
self.layout.setContentsMargins(margins["left"], margins["top"],
|
||||
margins["right"], margins["bottom"])
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.chumopen = False
|
||||
|
||||
if parent:
|
||||
parent.addChat(self)
|
||||
if initiated:
|
||||
msg = self.mainwindow.profile().pestermsg(self.chum, QtGui.QColor(self.mainwindow.theme["convo/systemMsgColor"]), self.mainwindow.theme["convo/text/beganpester"])
|
||||
self.setChumOpen(True)
|
||||
self.textArea.append(convertTags(msg))
|
||||
self.mainwindow.chatlog.log(self.chum.handle, convertTags(msg, "bbcode"))
|
||||
self.newmessage = False
|
||||
|
||||
def updateMood(self, mood, unblocked=False):
|
||||
if mood.name() == "offline" and self.chumopen == True and not unblocked:
|
||||
msg = self.chum.pestermsg(self.mainwindow.profile(), QtGui.QColor(self.mainwindow.theme["convo/systemMsgColor"]), self.mainwindow.theme["convo/text/ceasepester"])
|
||||
self.textArea.append(convertTags(msg))
|
||||
self.mainwindow.chatlog.log(self.chum.handle, convertTags(msg, "bbcode"))
|
||||
self.chumopen = False
|
||||
if self.parent():
|
||||
self.parent().updateMood(self.chum.handle, mood, unblocked)
|
||||
else:
|
||||
if self.chum.blocked(self.mainwindow.config) and not unblocked:
|
||||
self.setWindowIcon(QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"]))
|
||||
else:
|
||||
self.setWindowIcon(mood.icon(self.mainwindow.theme))
|
||||
# print mood update?
|
||||
def updateBlocked(self):
|
||||
if self.parent():
|
||||
self.parent().updateBlocked(self.chum.handle)
|
||||
else:
|
||||
self.setWindowIcon(QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"]))
|
||||
def updateColor(self, color):
|
||||
self.chum.color = color
|
||||
def addMessage(self, text, me=True):
|
||||
if me:
|
||||
chum = self.mainwindow.profile()
|
||||
else:
|
||||
chum = self.chum
|
||||
self.notifyNewMessage()
|
||||
self.textArea.addMessage(text, chum)
|
||||
|
||||
def notifyNewMessage(self):
|
||||
# first see if this conversation HASS the focus
|
||||
if not (self.hasFocus() or self.textArea.hasFocus() or
|
||||
self.textInput.hasFocus() or
|
||||
(self.parent() and self.parent().convoHasFocus(self.chum.handle))):
|
||||
# ok if it has a tabconvo parent, send that the notify.
|
||||
if self.parent():
|
||||
self.parent().notifyNewMessage(self.chum.handle)
|
||||
# if not change the window title and update system tray
|
||||
else:
|
||||
self.newmessage = True
|
||||
self.setWindowTitle(self.chum.handle+"*")
|
||||
def func():
|
||||
self.showChat()
|
||||
self.mainwindow.waitingMessages.addMessage(self.chum.handle, func)
|
||||
|
||||
def clearNewMessage(self):
|
||||
if self.parent():
|
||||
self.parent().clearNewMessage(self.chum.handle)
|
||||
elif self.newmessage:
|
||||
self.newmessage = False
|
||||
self.setWindowTitle(self.chum.handle)
|
||||
self.mainwindow.waitingMessages.messageAnswered(self.chum.handle)
|
||||
# reset system tray
|
||||
def focusInEvent(self, event):
|
||||
self.clearNewMessage()
|
||||
self.textInput.setFocus()
|
||||
def raiseChat(self):
|
||||
self.activateWindow()
|
||||
self.raise_()
|
||||
self.textInput.setFocus()
|
||||
|
||||
def showChat(self):
|
||||
if self.parent():
|
||||
self.parent().showChat(self.chum.handle)
|
||||
self.raiseChat()
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.mainwindow.waitingMessages.messageAnswered(self.chum.handle)
|
||||
self.windowClosed.emit(self.chum.handle)
|
||||
def setChumOpen(self, o):
|
||||
self.chumopen = o
|
||||
def changeTheme(self, theme):
|
||||
self.resize(*theme["convo/size"])
|
||||
self.setStyleSheet(theme["convo/style"])
|
||||
margins = theme["convo/margins"]
|
||||
self.layout.setContentsMargins(margins["left"], margins["top"],
|
||||
margins["right"], margins["bottom"])
|
||||
|
||||
self.setWindowIcon(self.chum.mood.icon(theme))
|
||||
t = Template(self.mainwindow.theme["convo/chumlabel/text"])
|
||||
self.chumLabel.setText(t.safe_substitute(handle=self.chum.handle))
|
||||
self.chumLabel.setStyleSheet(theme["convo/chumlabel/style"])
|
||||
self.chumLabel.setAlignment(self.aligndict["h"][self.mainwindow.theme["convo/chumlabel/align/h"]] | self.aligndict["v"][self.mainwindow.theme["convo/chumlabel/align/v"]])
|
||||
self.chumLabel.setMaximumHeight(self.mainwindow.theme["convo/chumlabel/maxheight"])
|
||||
self.chumLabel.setMinimumHeight(self.mainwindow.theme["convo/chumlabel/minheight"])
|
||||
self.chumLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding))
|
||||
self.textArea.changeTheme(theme)
|
||||
self.textInput.changeTheme(theme)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def sentMessage(self):
|
||||
text = self.textInput.text()
|
||||
if text == "":
|
||||
return
|
||||
# deal with quirks here
|
||||
qtext = self.mainwindow.userprofile.quirks.apply(unicode(text))
|
||||
text = QtCore.QString(qtext)
|
||||
self.textInput.setText("")
|
||||
self.addMessage(text, True)
|
||||
# if ceased, rebegin
|
||||
if not self.chumopen:
|
||||
self.mainwindow.newConvoStarted.emit(QtCore.QString(self.chum.handle), True)
|
||||
# convert color tags
|
||||
text = convertTags(unicode(text), "ctag")
|
||||
self.messageSent.emit(text, self.chum)
|
||||
|
||||
messageSent = QtCore.pyqtSignal(QtCore.QString, PesterProfile)
|
||||
windowClosed = QtCore.pyqtSignal(QtCore.QString)
|
||||
|
||||
aligndict = {"h": {"center": QtCore.Qt.AlignHCenter,
|
||||
"left": QtCore.Qt.AlignLeft,
|
||||
"right": QtCore.Qt.AlignRight },
|
||||
"v": {"center": QtCore.Qt.AlignVCenter,
|
||||
"top": QtCore.Qt.AlignTop,
|
||||
"bottom": QtCore.Qt.AlignBottom } }
|
BIN
convo.pyc
Normal file
BIN
convo.pyc
Normal file
Binary file not shown.
|
@ -6,9 +6,10 @@ from generic import PesterIcon
|
|||
|
||||
class Mood(object):
|
||||
moods = ["chummy", "rancorous", "offline", "pleasant", "distraught",
|
||||
"unruly", "smooth", "ecstatic", "relaxed", "discontent",
|
||||
"pranky", "smooth", "ecstatic", "relaxed", "discontent",
|
||||
"devious", "sleek", "detestful", "mirthful", "manipulative",
|
||||
"vigorous", "perky", "acceptant", "protective"]
|
||||
"vigorous", "perky", "acceptant", "protective", "mystified",
|
||||
"amazed", "insolent", "bemused" ]
|
||||
def __init__(self, mood):
|
||||
if type(mood) is int:
|
||||
self.mood = mood
|
||||
|
@ -66,14 +67,23 @@ class pesterQuirks(object):
|
|||
def plainList(self):
|
||||
return [q.quirk for q in self.quirklist]
|
||||
def apply(self, string):
|
||||
# don't quirk /me commands
|
||||
if string[0:3] == "/me":
|
||||
space = string.find(" ")
|
||||
cmd = string[0:space]
|
||||
string = string[space:]
|
||||
else:
|
||||
cmd = ""
|
||||
presuffix = [q for q in self.quirklist if
|
||||
q.type=='prefix' or q.type=='suffix']
|
||||
replace = [q for q in self.quirklist if
|
||||
q.type=='replace' or q.type=='regexp']
|
||||
for r in replace:
|
||||
string = r.apply(string)
|
||||
for ps in presuffix:
|
||||
string = ps.apply(string)
|
||||
if not cmd:
|
||||
for ps in presuffix:
|
||||
string = ps.apply(string)
|
||||
string = cmd+string
|
||||
return string
|
||||
|
||||
def __iter__(self):
|
BIN
dataobjs.pyc
Normal file
BIN
dataobjs.pyc
Normal file
Binary file not shown.
|
@ -1 +1 @@
|
|||
{"macruralAlchemist": {"color": "#700000", "handle": "macruralAlchemist", "mood": "offline"}, "agogPorphyry": {"color": "#522d80", "handle": "agogPorphyry", "mood": "offline"}, "fireSwallow": {"color": "#80bb9a", "handle": "fireSwallow", "mood": "offline"}, "aquaMarinist": {"color": "#00caca", "handle": "aquaMarinist", "mood": "offline"}, "nitroZealist": {"color": "#ff3737", "handle": "nitroZealist", "mood": "offline"}, "superGhost": {"color": "#800564", "handle": "superGhost", "mood": "offline"}, "tentacleTherapist": {"color": "#cc66ff", "handle": "tentacleTherapist", "mood": "offline"}, "aquaticMarinist": {"color": "#00caca", "handle": "aquaticMarinist", "mood": "offline"}, "marineAquist": {"color": "#00caca", "handle": "marineAquist", "mood": "offline"}, "captainCaveman": {"color": "#7c414e", "handle": "captainCaveman", "mood": "offline"}, "gamblingGenocider": {"color": "#00ff00", "handle": "gamblingGenocider", "mood": "offline"}, "mechanicalSpectacle": {"color": "#0000ff", "handle": "mechanicalSpectacle", "mood": "offline"}, "absoluteTranquility": {"color": "#000033", "handle": "absoluteTranquility", "mood": "offline"}, "centaursTesticle": {"color": "#000056", "handle": "centaursTesticle", "mood": "offline"}, "gardenGnostic": {"color": "#00ff00", "handle": "gardenGnostic", "mood": "offline"}, "unknownTraveler": {"color": "#006666", "handle": "unknownTraveler", "mood": "offline"}, "schlagzeugGator": {"color": "#61821f", "handle": "schlagzeugGator", "mood": "offline"}}
|
||||
{"macruralAlchemist": {"color": "#700000", "handle": "macruralAlchemist", "mood": "offline"}, "agogPorphyry": {"color": "#522d80", "handle": "agogPorphyry", "mood": "offline"}, "fireSwallow": {"color": "#80bb9a", "handle": "fireSwallow", "mood": "offline"}, "aquaMarinist": {"color": "#00caca", "handle": "aquaMarinist", "mood": "offline"}, "nitroZealist": {"color": "#ff3737", "handle": "nitroZealist", "mood": "offline"}, "superGhost": {"color": "#800564", "handle": "superGhost", "mood": "offline"}, "tentacleTherapist": {"color": "#cc66ff", "handle": "tentacleTherapist", "mood": "offline"}, "gardenGnostic": {"color": "#00ff00", "handle": "gardenGnostic", "mood": "offline"}, "aquaticMarinist": {"color": "#00caca", "handle": "aquaticMarinist", "mood": "offline"}, "captainCaveman": {"color": "#7c414e", "handle": "captainCaveman", "mood": "offline"}, "greenZephyr": {"color": "#00ca40", "handle": "greenZephyr", "mood": "offline"}, "pesterClient394": {"color": "#ff3737", "handle": "pesterClient394", "mood": "offline"}, "gamblingGenocider": {"color": "#00ff00", "handle": "gamblingGenocider", "mood": "offline"}, "mechanicalSpectacle": {"color": "#0000ff", "handle": "mechanicalSpectacle", "mood": "offline"}, "elegantDiversion": {"color": "#12b40d", "handle": "elegantDiversion", "mood": "offline"}, "absoluteTranquility": {"color": "#000033", "handle": "absoluteTranquility", "mood": "offline"}, "centaursTesticle": {"color": "#000056", "handle": "centaursTesticle", "mood": "offline"}, "schlagzeugGator": {"color": "#61821f", "handle": "schlagzeugGator", "mood": "offline"}, "unknownTraveler": {"color": "#006666", "handle": "unknownTraveler", "mood": "offline"}, "remoteBloodbath": {"color": "#c70000", "handle": "remoteBloodbath", "mood": "offline"}, "marineAquist": {"color": "#00caca", "handle": "marineAquist", "mood": "offline"}}
|
125
memos.py
Normal file
125
memos.py
Normal file
|
@ -0,0 +1,125 @@
|
|||
from string import Template
|
||||
import re
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
from dataobjs import PesterProfile, Mood
|
||||
from generic import PesterIcon
|
||||
from convo import PesterConvo, PesterInput, PesterText
|
||||
|
||||
class MemoText(PesterText):
|
||||
def __init__(self, theme, parent=None):
|
||||
QtGui.QTextEdit.__init__(self, parent)
|
||||
self.setStyleSheet(theme["memos/textarea/style"])
|
||||
self.setReadOnly(True)
|
||||
self.setMouseTracking(True)
|
||||
def addMessage(self, text, chum):
|
||||
pass
|
||||
def changeTheme(self):
|
||||
pass
|
||||
|
||||
class MemoInput(PesterInput):
|
||||
def __init__(self, theme, parent=None):
|
||||
QtGui.QLineEdit.__init__(self, parent)
|
||||
self.setStyleSheet(theme["memos/input/style"])
|
||||
def changeTheme(self, theme):
|
||||
self.setStyleSheet(theme["memos/input/style"])
|
||||
|
||||
class PesterMemo(PesterConvo):
|
||||
def __init__(self, channel, mainwindow, parent=None):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
self.channel = channel
|
||||
self.mainwindow = mainwindow
|
||||
self.setWindowTitle(channel)
|
||||
self.channelLabel = QtGui.QLabel(self)
|
||||
self.channelLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding))
|
||||
|
||||
self.textArea = MemoText(self.mainwindow.theme, self)
|
||||
self.textInput = MemoInput(self.mainwindow.theme, self)
|
||||
self.textInput.setFocus()
|
||||
|
||||
self.userlist = QtGui.QListWidget(self)
|
||||
self.userlist.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding))
|
||||
|
||||
self.timeslider = QtGui.QSlider(QtCore.Qt.Vertical, self)
|
||||
self.timeinput = QtGui.QLineEdit(self)
|
||||
|
||||
self.initTheme(self.mainwindow.theme)
|
||||
|
||||
# connect
|
||||
layout_0 = QtGui.QVBoxLayout()
|
||||
layout_0.addWidget(self.channelLabel)
|
||||
layout_0.addWidget(self.textArea)
|
||||
layout_0.addWidget(self.textInput)
|
||||
|
||||
layout_1 = QtGui.QGridLayout()
|
||||
layout_1.addWidget(self.timeslider, 0, 1, QtCore.Qt.AlignHCenter)
|
||||
layout_1.addWidget(self.timeinput, 1, 0, 1, 3)
|
||||
|
||||
self.layout = QtGui.QHBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.layout.addLayout(layout_0)
|
||||
self.layout.addWidget(self.userlist)
|
||||
self.layout.addLayout(layout_1)
|
||||
self.layout.setSpacing(0)
|
||||
margins = self.mainwindow.theme["memos/margins"]
|
||||
self.layout.setContentsMargins(margins["left"], margins["top"],
|
||||
margins["right"], margins["bottom"])
|
||||
|
||||
#if parent:
|
||||
# parent.addChat(self)
|
||||
self.newmessage = False
|
||||
|
||||
def updateMood(self):
|
||||
pass
|
||||
def updateBlocked(self):
|
||||
pass
|
||||
def updateColor(self):
|
||||
pass
|
||||
def addMessage(self):
|
||||
pass
|
||||
def notifyNewMessage(self):
|
||||
pass
|
||||
def clearNewMessage(self):
|
||||
pass
|
||||
|
||||
def initTheme(self, theme):
|
||||
memo = theme["memos"]
|
||||
self.resize(*memo["size"])
|
||||
self.setStyleSheet(memo["style"])
|
||||
self.setWindowIcon(PesterIcon(theme["memos/memoicon"]))
|
||||
|
||||
t = Template(theme["memos/label/text"])
|
||||
self.channelLabel.setText(t.safe_substitute(channel=self.channel))
|
||||
self.channelLabel.setStyleSheet(theme["memos/label/style"])
|
||||
self.channelLabel.setAlignment(self.aligndict["h"][theme["memos/label/align/h"]] | self.aligndict["v"][theme["memos/label/align/v"]])
|
||||
self.channelLabel.setMaximumHeight(theme["memos/label/maxheight"])
|
||||
self.channelLabel.setMinimumHeight(theme["memos/label/minheight"])
|
||||
|
||||
self.userlist.setStyleSheet(theme["main/chums/style"])
|
||||
self.userlist.setFixedWidth(theme["memos/userlist/width"])
|
||||
|
||||
self.timeinput.setFixedWidth(theme["memos/time/text/width"])
|
||||
self.timeinput.setStyleSheet(theme["memos/time/text/style"])
|
||||
slidercss = "QSlider { %s } QSlider::groove { %s } QSlider::handle { %s }" % (theme["memos/time/slider/style"], theme["memos/time/slider/groove"], theme["memos/time/slider/handle"])
|
||||
self.timeslider.setStyleSheet(slidercss)
|
||||
|
||||
|
||||
def changeTheme(self, theme):
|
||||
self.initTheme(theme)
|
||||
self.textArea.changeTheme(theme)
|
||||
self.textInput.changeTheme(theme)
|
||||
|
||||
def sentMessage(self):
|
||||
pass
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.mainwindow.waitingMessages.messageAnswered(self.channel)
|
||||
# self.windowClosed.emit(self.chum.handle)
|
||||
|
||||
|
||||
# messageSent - signal -> sendMessage -> sendMessage(Memo)
|
||||
# windowClosed - signal -> closeMemo
|
||||
|
||||
# self.textInput
|
||||
# self.textArea
|
BIN
memos.pyc
Normal file
BIN
memos.pyc
Normal file
Binary file not shown.
|
@ -376,7 +376,6 @@ class PesterUserlist(QtGui.QDialog):
|
|||
self.userarea.setStyleSheet(theme["main/chums/style"])
|
||||
self.addChumAction.setText(theme["main/menus/rclickchumlist/addchum"])
|
||||
for item in [self.userarea.item(i) for i in range(0, self.userarea.count())]:
|
||||
print item.text()
|
||||
item.setTextColor(QtGui.QColor(theme["main/chums/userlistcolor"]))
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
|
@ -388,3 +387,66 @@ class PesterUserlist(QtGui.QDialog):
|
|||
|
||||
addChum = QtCore.pyqtSignal(QtCore.QString)
|
||||
|
||||
class PesterMemoList(QtGui.QDialog):
|
||||
def __init__(self, parent):
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.setModal(False)
|
||||
self.theme = parent.theme
|
||||
self.mainwindow = parent
|
||||
self.setStyleSheet(self.theme["main/defaultwindow/style"])
|
||||
self.resize(200, 300)
|
||||
|
||||
self.label = QtGui.QLabel("MEMOS")
|
||||
self.channelarea = RightClickList(self)
|
||||
self.channelarea.setStyleSheet(self.theme["main/chums/style"])
|
||||
self.channelarea.optionsMenu = QtGui.QMenu(self)
|
||||
self.connect(self.channelarea,
|
||||
QtCore.SIGNAL('itemActivated(QListWidgetItem *)'),
|
||||
self, QtCore.SLOT('joinActivatedMemo(QListWidgetItem *)'))
|
||||
|
||||
self.orjoinlabel = QtGui.QLabel("OR MAKE A NEW MEMO:")
|
||||
self.newmemo = QtGui.QLineEdit(self)
|
||||
|
||||
self.cancel = QtGui.QPushButton("CANCEL", self)
|
||||
self.connect(self.cancel, QtCore.SIGNAL('clicked()'),
|
||||
self, QtCore.SLOT('reject()'))
|
||||
self.join = QtGui.QPushButton("JOIN", self)
|
||||
self.join.setDefault(True)
|
||||
self.connect(self.join, QtCore.SIGNAL('clicked()'),
|
||||
self, QtCore.SLOT('accept()'))
|
||||
layout_ok = QtGui.QHBoxLayout()
|
||||
layout_ok.addWidget(self.cancel)
|
||||
layout_ok.addWidget(self.join)
|
||||
|
||||
layout_0 = QtGui.QVBoxLayout()
|
||||
layout_0.addWidget(self.label)
|
||||
layout_0.addWidget(self.channelarea)
|
||||
layout_0.addWidget(self.orjoinlabel)
|
||||
layout_0.addWidget(self.newmemo)
|
||||
layout_0.addLayout(layout_ok)
|
||||
|
||||
self.setLayout(layout_0)
|
||||
|
||||
def newmemoname(self):
|
||||
return self.newmemo.text()
|
||||
def selectedmemo(self):
|
||||
return self.channelarea.currentItem()
|
||||
|
||||
def updateChannels(self, channels):
|
||||
for c in channels:
|
||||
item = QtGui.QListWidgetItem(c[1:])
|
||||
item.setTextColor(QtGui.QColor(self.theme["main/chums/userlistcolor"]))
|
||||
item.setIcon(QtGui.QIcon(self.theme["memos/memoicon"]))
|
||||
self.channelarea.addItem(item)
|
||||
|
||||
def updateTheme(self, theme):
|
||||
self.theme = theme
|
||||
self.setStyleSheet(theme["main/defaultwindow/style"])
|
||||
for item in [self.userarea.item(i) for i in range(0, self.channelarea.count())]:
|
||||
item.setTextColor(QtGui.QColor(theme["main/chums/userlistcolor"]))
|
||||
item.setIcon(QtGui.QIcon(theme["memos/memoicon"]))
|
||||
|
||||
@QtCore.pyqtSlot(QtGui.QListWidgetItem)
|
||||
def joinActivatedMemo(self, item):
|
||||
self.channelarea.setCurrentItem(item)
|
||||
self.accept()
|
BIN
menus.pyc
Normal file
BIN
menus.pyc
Normal file
Binary file not shown.
|
@ -35,6 +35,9 @@ def names(cli, *channels):
|
|||
if len(msglist) > 0:
|
||||
cli.send("NAMES %s" % (",".join(msglist)))
|
||||
|
||||
def channel_list(cli):
|
||||
cli.send("LIST")
|
||||
|
||||
def msgrandom(cli, choices, dest, user=None):
|
||||
o = "%s: " % user if user else ""
|
||||
o += random.choice(choices)
|
||||
|
|
Binary file not shown.
89
parsetools.py
Normal file
89
parsetools.py
Normal file
|
@ -0,0 +1,89 @@
|
|||
import re
|
||||
from PyQt4 import QtGui
|
||||
|
||||
_ctag_begin = re.compile(r'<c=(.*?)>')
|
||||
_ctag_rgb = re.compile(r'\d+,\d+,\d+')
|
||||
_urlre = re.compile(r"(?i)(http://[^\s<]+)")
|
||||
|
||||
def convertTags(string, format="html"):
|
||||
if format not in ["html", "bbcode", "ctag"]:
|
||||
raise ValueError("Color format not recognized")
|
||||
def colorrepfunc(matchobj):
|
||||
color = matchobj.group(1)
|
||||
if _ctag_rgb.match(color) is not None:
|
||||
if format=='ctag':
|
||||
return "<c=%s,%s,%s>"
|
||||
try:
|
||||
qc = QtGui.QColor(*[int(c) for c in color.split(",")])
|
||||
except ValueError:
|
||||
qc = QtGui.QColor("black")
|
||||
else:
|
||||
qc = QtGui.QColor(color)
|
||||
if not qc.isValid():
|
||||
qc = QtGui.QColor("black")
|
||||
if format == "html":
|
||||
return '<span style="color:%s">' % (qc.name())
|
||||
elif format == "bbcode":
|
||||
return '[color=%s]' % (qc.name())
|
||||
elif format == "ctag":
|
||||
(r,g,b,a) = qc.getRgb()
|
||||
return '<c=%s,%s,%s>' % (r,g,b)
|
||||
string = _ctag_begin.sub(colorrepfunc, string)
|
||||
endtag = {"html": "</span>", "bbcode": "[/color]", "ctag": "</c>"}
|
||||
string = string.replace("</c>", endtag[format])
|
||||
def urlrep(matchobj):
|
||||
if format=="html":
|
||||
return "<a href='%s'>%s</a>" % (matchobj.group(1).replace("&", "&"), matchobj.group(1))
|
||||
elif format=="bbcode":
|
||||
return "[url]%s[/url]" % (matchobj.group(1).replace("&", "&"))
|
||||
elif format=="ctag":
|
||||
return matchobj.group(1)
|
||||
string = _urlre.sub(urlrep, string)
|
||||
return string
|
||||
|
||||
def escapeBrackets(string):
|
||||
class beginTag(object):
|
||||
def __init__(self, tag):
|
||||
self.tag = tag
|
||||
class endTag(object):
|
||||
pass
|
||||
newlist = []
|
||||
begintagpos = [(m.start(), m.end()) for m in _ctag_begin.finditer(string)]
|
||||
lasti = 0
|
||||
for (s, e) in begintagpos:
|
||||
newlist.append(string[lasti:s])
|
||||
newlist.append(beginTag(string[s:e]))
|
||||
lasti = e
|
||||
if lasti < len(string):
|
||||
newlist.append(string[lasti:])
|
||||
tmp = []
|
||||
for o in newlist:
|
||||
if type(o) is not beginTag:
|
||||
l = o.split("</c>")
|
||||
tmp.append(l[0])
|
||||
l = l[1:]
|
||||
for item in l:
|
||||
tmp.append(endTag())
|
||||
tmp.append(item)
|
||||
else:
|
||||
tmp.append(o)
|
||||
btlen = 0
|
||||
etlen = 0
|
||||
retval = ""
|
||||
newlist = tmp
|
||||
for o in newlist:
|
||||
if type(o) is beginTag:
|
||||
retval += o.tag.replace("&", "&")
|
||||
btlen +=1
|
||||
elif type(o) is endTag:
|
||||
if etlen >= btlen:
|
||||
continue
|
||||
else:
|
||||
retval += "</c>"
|
||||
etlen += 1
|
||||
else:
|
||||
retval += o.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
if btlen > etlen:
|
||||
for i in range(0, btlen-etlen):
|
||||
retval += "</c>"
|
||||
return retval
|
BIN
parsetools.pyc
Normal file
BIN
parsetools.pyc
Normal file
Binary file not shown.
|
@ -1 +1 @@
|
|||
{"tabs": true, "chums": ["aquaMarinist", "marineAquist", "unknownTraveler", "tentacleTherapist", "macruralAlchemist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "fireSwallow", "grimAuxiliatrix"], "defaultprofile": "ghostDunk", "block": []}
|
||||
{"tabs": false, "chums": ["aquaMarinist", "marineAquist", "unknownTraveler", "tentacleTherapist", "macruralAlchemist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "fireSwallow", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr"], "defaultprofile": "testProfile", "block": []}
|
609
pesterchum.py
609
pesterchum.py
|
@ -13,95 +13,16 @@ import re
|
|||
from PyQt4 import QtGui, QtCore
|
||||
import pygame
|
||||
|
||||
from pestermenus import PesterChooseQuirks, PesterChooseTheme, \
|
||||
PesterChooseProfile, PesterOptions, PesterUserlist
|
||||
from pesterdata import PesterProfile, Mood, pesterQuirk, pesterQuirks
|
||||
from menus import PesterChooseQuirks, PesterChooseTheme, \
|
||||
PesterChooseProfile, PesterOptions, PesterUserlist, PesterMemoList
|
||||
from dataobjs import PesterProfile, Mood, pesterQuirk, pesterQuirks
|
||||
from generic import PesterIcon, RightClickList, MultiTextDialog
|
||||
from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo
|
||||
from parsetools import convertTags
|
||||
from memos import PesterMemo
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
_ctag_begin = re.compile(r'<c=(.*?)>')
|
||||
_ctag_rgb = re.compile(r'\d+,\d+,\d+')
|
||||
_urlre = re.compile(r"(?i)(http://[^\s<]+)")
|
||||
|
||||
def convertTags(string, format="html"):
|
||||
if format not in ["html", "bbcode", "ctag"]:
|
||||
raise ValueError("Color format not recognized")
|
||||
def colorrepfunc(matchobj):
|
||||
color = matchobj.group(1)
|
||||
if _ctag_rgb.match(color) is not None:
|
||||
if format=='ctag':
|
||||
return "<c=%s,%s,%s>"
|
||||
try:
|
||||
qc = QtGui.QColor(*[int(c) for c in color.split(",")])
|
||||
except ValueError:
|
||||
qc = QtGui.QColor("black")
|
||||
else:
|
||||
qc = QtGui.QColor(color)
|
||||
if not qc.isValid():
|
||||
qc = QtGui.QColor("black")
|
||||
if format == "html":
|
||||
return '<span style="color:%s">' % (qc.name())
|
||||
elif format == "bbcode":
|
||||
return '[color=%s]' % (qc.name())
|
||||
elif format == "ctag":
|
||||
(r,g,b,a) = qc.getRgb()
|
||||
return '<c=%s,%s,%s>' % (r,g,b)
|
||||
string = _ctag_begin.sub(colorrepfunc, string)
|
||||
endtag = {"html": "</span>", "bbcode": "[/color]", "ctag": "</c>"}
|
||||
string = string.replace("</c>", endtag[format])
|
||||
urlrep = {"html": r"<a href='\1'>\1</a>",
|
||||
"bbcode": r"[url]\1[/url]",
|
||||
"ctag": r"\1" }
|
||||
string = _urlre.sub(urlrep[format], string)
|
||||
return string
|
||||
|
||||
def escapeBrackets(string):
|
||||
class beginTag(object):
|
||||
def __init__(self, tag):
|
||||
self.tag = tag
|
||||
class endTag(object):
|
||||
pass
|
||||
newlist = []
|
||||
begintagpos = [(m.start(), m.end()) for m in _ctag_begin.finditer(string)]
|
||||
lasti = 0
|
||||
for (s, e) in begintagpos:
|
||||
newlist.append(string[lasti:s])
|
||||
newlist.append(beginTag(string[s:e]))
|
||||
lasti = e
|
||||
if lasti < len(string):
|
||||
newlist.append(string[lasti:])
|
||||
tmp = []
|
||||
for o in newlist:
|
||||
if type(o) is not beginTag:
|
||||
l = o.split("</c>")
|
||||
tmp.append(l[0])
|
||||
l = l[1:]
|
||||
for item in l:
|
||||
tmp.append(endTag())
|
||||
tmp.append(item)
|
||||
else:
|
||||
tmp.append(o)
|
||||
btlen = 0
|
||||
etlen = 0
|
||||
retval = ""
|
||||
newlist = tmp
|
||||
for o in newlist:
|
||||
if type(o) is beginTag:
|
||||
retval += o.tag.replace("&", "&")
|
||||
btlen +=1
|
||||
elif type(o) is endTag:
|
||||
if etlen >= btlen:
|
||||
continue
|
||||
else:
|
||||
retval += "</c>"
|
||||
etlen += 1
|
||||
else:
|
||||
retval += o.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
if btlen > etlen:
|
||||
for i in range(0, btlen-etlen):
|
||||
retval += "</c>"
|
||||
return retval
|
||||
|
||||
class waitingMessageHolder(object):
|
||||
def __init__(self, mainwindow, **msgfuncs):
|
||||
|
@ -140,7 +61,7 @@ class PesterLog(object):
|
|||
self.convos = {}
|
||||
def log(self, handle, msg):
|
||||
if not self.convos.has_key(handle):
|
||||
time = datetime.now().strftime("%Y-%m-%d.%H:%M")
|
||||
time = datetime.now().strftime("%Y-%m-%d.%H.%M.txt")
|
||||
if not os.path.exists("logs/%s/%s" % (self.handle, handle)):
|
||||
os.mkdir("logs/%s/%s" % (self.handle, handle))
|
||||
fp = open("logs/%s/%s/%s.%s" % (self.handle, handle, handle, time), 'a')
|
||||
|
@ -652,422 +573,6 @@ class MovingWindow(QtGui.QFrame):
|
|||
self.update()
|
||||
self.moving = None
|
||||
|
||||
class PesterTabWindow(QtGui.QFrame):
|
||||
def __init__(self, mainwindow, parent=None):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
self.setFocusPolicy(QtCore.Qt.ClickFocus)
|
||||
self.mainwindow = mainwindow
|
||||
self.resize(*self.mainwindow.theme["convo/size"])
|
||||
self.setStyleSheet(self.mainwindow.theme["convo/style"])
|
||||
|
||||
self.tabs = QtGui.QTabBar(self)
|
||||
self.tabs.setTabsClosable(True)
|
||||
self.connect(self.tabs, QtCore.SIGNAL('currentChanged(int)'),
|
||||
self, QtCore.SLOT('changeTab(int)'))
|
||||
self.connect(self.tabs, QtCore.SIGNAL('tabCloseRequested(int)'),
|
||||
self, QtCore.SLOT('tabClose(int)'))
|
||||
self.tabs.setShape(self.mainwindow.theme["convo/tabs/tabstyle"])
|
||||
self.tabs.setStyleSheet("QTabBar::tab{ %s } QTabBar::tab:selected { %s }" % (self.mainwindow.theme["convo/tabs/style"], self.mainwindow.theme["convo/tabs/selectedstyle"]))
|
||||
|
||||
self.layout = QtGui.QVBoxLayout()
|
||||
self.layout.setContentsMargins(0,0,0,0)
|
||||
self.layout.addWidget(self.tabs)
|
||||
self.setLayout(self.layout)
|
||||
self.convos = {}
|
||||
self.tabIndices = {}
|
||||
self.currentConvo = None
|
||||
self.changedTab = False
|
||||
self.softclose = False
|
||||
|
||||
# get default tab color i guess
|
||||
self.defaultTabTextColor = self.getTabTextColor()
|
||||
def getTabTextColor(self):
|
||||
# ugly, ugly hack
|
||||
self.changedTab = True
|
||||
i = self.tabs.addTab(".")
|
||||
c = self.tabs.tabTextColor(i)
|
||||
self.tabs.removeTab(i)
|
||||
self.changedTab = False
|
||||
return c
|
||||
def addChat(self, convo):
|
||||
self.convos[convo.chum.handle] = convo
|
||||
# either addTab or setCurrentIndex will trigger changed()
|
||||
newindex = self.tabs.addTab(convo.chum.handle)
|
||||
self.tabIndices[convo.chum.handle] = newindex
|
||||
self.tabs.setCurrentIndex(newindex)
|
||||
self.tabs.setTabIcon(newindex, convo.chum.mood.icon(self.mainwindow.theme))
|
||||
def showChat(self, handle):
|
||||
tabi = self.tabIndices[handle]
|
||||
if self.tabs.currentIndex() == tabi:
|
||||
self.activateWindow()
|
||||
self.raise_()
|
||||
self.convos[handle].raiseChat()
|
||||
else:
|
||||
self.tabs.setCurrentIndex(tabi)
|
||||
|
||||
def convoHasFocus(self, convo):
|
||||
if ((self.hasFocus() or self.tabs.hasFocus()) and
|
||||
self.tabs.tabText(self.tabs.currentIndex()) == convo.chum.handle):
|
||||
return True
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
keypress = event.key()
|
||||
mods = event.modifiers()
|
||||
if ((mods & QtCore.Qt.ControlModifier) and
|
||||
keypress == QtCore.Qt.Key_Tab):
|
||||
nexti = (self.tabIndices[self.currentConvo.chum.handle] + 1) % self.tabs.count()
|
||||
self.tabs.setCurrentIndex(nexti)
|
||||
|
||||
def closeSoft(self):
|
||||
self.softclose = True
|
||||
self.close()
|
||||
def updateBlocked(self, handle):
|
||||
i = self.tabIndices[handle]
|
||||
icon = QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"])
|
||||
self.tabs.setTabIcon(i, icon)
|
||||
if self.tabs.currentIndex() == i:
|
||||
self.setWindowIcon(icon)
|
||||
def updateMood(self, handle, mood, unblocked=False):
|
||||
i = self.tabIndices[handle]
|
||||
if handle in self.mainwindow.config.getBlocklist() and not unblocked:
|
||||
icon = QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"])
|
||||
else:
|
||||
icon = mood.icon(self.mainwindow.theme)
|
||||
self.tabs.setTabIcon(i, icon)
|
||||
if self.tabs.currentIndex() == i:
|
||||
self.setWindowIcon(icon)
|
||||
def closeEvent(self, event):
|
||||
if not self.softclose:
|
||||
while self.tabs.count() > 0:
|
||||
self.tabClose(0)
|
||||
self.windowClosed.emit()
|
||||
def focusInEvent(self, event):
|
||||
# make sure we're not switching tabs!
|
||||
i = self.tabs.tabAt(self.mapFromGlobal(QtGui.QCursor.pos()))
|
||||
if i == -1:
|
||||
i = self.tabs.currentIndex()
|
||||
handle = unicode(self.tabs.tabText(i))
|
||||
self.clearNewMessage(handle)
|
||||
def convoHasFocus(self, handle):
|
||||
i = self.tabIndices[handle]
|
||||
if (self.tabs.currentIndex() == i and
|
||||
(self.hasFocus() or self.tabs.hasFocus())):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def notifyNewMessage(self, handle):
|
||||
i = self.tabIndices[handle]
|
||||
self.tabs.setTabTextColor(i, QtGui.QColor(self.mainwindow.theme["convo/tabs/newmsgcolor"]))
|
||||
convo = self.convos[handle]
|
||||
def func():
|
||||
convo.showChat()
|
||||
self.mainwindow.waitingMessages.addMessage(handle, func)
|
||||
# set system tray
|
||||
def clearNewMessage(self, handle):
|
||||
try:
|
||||
i = self.tabIndices[handle]
|
||||
except KeyError:
|
||||
pass
|
||||
self.tabs.setTabTextColor(i, self.defaultTabTextColor)
|
||||
self.mainwindow.waitingMessages.messageAnswered(handle)
|
||||
def changeTheme(self, theme):
|
||||
self.resize(*theme["convo/size"])
|
||||
self.setStyleSheet(theme["convo/style"])
|
||||
self.tabs.setShape(theme["convo/tabs/tabstyle"])
|
||||
self.tabs.setStyleSheet("QTabBar::tabs{ %s }" % (theme["convo/tabs/style"]))
|
||||
for c in self.convos.values():
|
||||
tabi = self.tabIndices[c.chum.handle]
|
||||
self.tabs.setTabIcon(tabi, c.chum.mood.icon(theme))
|
||||
currenttabi = self.tabs.currentIndex()
|
||||
if currenttabi >= 0:
|
||||
currentHandle = unicode(self.tabs.tabText(self.tabs.currentIndex()))
|
||||
self.setWindowIcon(self.convos[currentHandle].chum.mood.icon(theme))
|
||||
self.defaultTabTextColor = self.getTabTextColor()
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def tabClose(self, i):
|
||||
handle = unicode(self.tabs.tabText(i))
|
||||
self.mainwindow.waitingMessages.messageAnswered(handle)
|
||||
convo = self.convos[handle]
|
||||
del self.convos[handle]
|
||||
del self.tabIndices[handle]
|
||||
self.tabs.removeTab(i)
|
||||
for (h, j) in self.tabIndices.iteritems():
|
||||
if j > i:
|
||||
self.tabIndices[h] = j-1
|
||||
self.layout.removeWidget(convo)
|
||||
convo.close()
|
||||
if self.tabs.count() == 0:
|
||||
self.close()
|
||||
return
|
||||
if self.currentConvo == convo:
|
||||
currenti = self.tabs.currentIndex()
|
||||
currenth = unicode(self.tabs.tabText(currenti))
|
||||
self.currentConvo = self.convos[currenth]
|
||||
self.currentConvo.raiseChat()
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def changeTab(self, i):
|
||||
if i < 0:
|
||||
return
|
||||
if self.changedTab:
|
||||
self.changedTab = False
|
||||
return
|
||||
handle = unicode(self.tabs.tabText(i))
|
||||
convo = self.convos[handle]
|
||||
if self.currentConvo:
|
||||
self.layout.removeWidget(self.currentConvo)
|
||||
self.currentConvo = convo
|
||||
self.layout.addWidget(convo)
|
||||
self.setWindowIcon(convo.chum.mood.icon(self.mainwindow.theme))
|
||||
self.setWindowTitle(convo.chum.handle)
|
||||
self.activateWindow()
|
||||
self.raise_()
|
||||
convo.raiseChat()
|
||||
|
||||
windowClosed = QtCore.pyqtSignal()
|
||||
|
||||
class PesterText(QtGui.QTextEdit):
|
||||
def __init__(self, theme, parent=None):
|
||||
QtGui.QTextEdit.__init__(self, parent)
|
||||
self.setStyleSheet(theme["convo/textarea/style"])
|
||||
self.setReadOnly(True)
|
||||
def addMessage(self, text, chum):
|
||||
color = chum.colorhtml()
|
||||
systemColor = QtGui.QColor(self.parent().mainwindow.theme["convo/systemMsgColor"])
|
||||
initials = chum.initials()
|
||||
msg = unicode(text)
|
||||
parent = self.parent()
|
||||
window = parent.mainwindow
|
||||
me = window.profile()
|
||||
if msg == "PESTERCHUM:BEGIN":
|
||||
parent.setChumOpen(True)
|
||||
msg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"])
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
elif msg == "PESTERCHUM:CEASE":
|
||||
parent.setChumOpen(False)
|
||||
msg = chum.pestermsg(me, systemColor, window.theme["convo/text/ceasepester"])
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
elif msg == "PESTERCHUM:BLOCK":
|
||||
msg = chum.pestermsg(me, systemColor, window.theme['convo/text/blocked'])
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
elif msg == "PESTERCHUM:UNBLOCK":
|
||||
msg = chum.pestermsg(me, systemColor, window.theme['convo/text/unblocked'])
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
elif msg[0:3] == "/me" or msg[0:13] == "PESTERCHUM:ME":
|
||||
if msg[0:3] == "/me":
|
||||
start = 3
|
||||
else:
|
||||
start = 13
|
||||
space = msg.find(" ")
|
||||
msg = chum.memsg(systemColor, msg[start:space], msg[space:])
|
||||
if chum is me:
|
||||
window.chatlog.log(parent.chum.handle, convertTags(msg, "bbcode"))
|
||||
else:
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
self.append(convertTags(msg))
|
||||
else:
|
||||
if not parent.chumopen and chum is not me:
|
||||
beginmsg = chum.pestermsg(me, systemColor, window.theme["convo/text/beganpester"])
|
||||
parent.setChumOpen(True)
|
||||
window.chatlog.log(chum.handle, convertTags(beginmsg, "bbcode"))
|
||||
self.append(convertTags(beginmsg))
|
||||
|
||||
msg = "<c=%s>%s: %s</c>" % (color, initials, msg)
|
||||
msg = escapeBrackets(msg)
|
||||
self.append(convertTags(msg))
|
||||
if chum is me:
|
||||
window.chatlog.log(parent.chum.handle, convertTags(msg, "bbcode"))
|
||||
else:
|
||||
window.chatlog.log(chum.handle, convertTags(msg, "bbcode"))
|
||||
def changeTheme(self, theme):
|
||||
self.setStyleSheet(theme["convo/textarea/style"])
|
||||
sb = self.verticalScrollBar()
|
||||
sb.setMaximum(sb.maximum()+1000) # ugly hack but whatcha gonna do
|
||||
sb.setValue(sb.maximum())
|
||||
def focusInEvent(self, event):
|
||||
self.parent().clearNewMessage()
|
||||
QtGui.QTextEdit.focusInEvent(self, event)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
url = self.anchorAt(event.pos())
|
||||
if url != "":
|
||||
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode))
|
||||
QtGui.QTextEdit.mousePressEvent(self, event)
|
||||
|
||||
class PesterInput(QtGui.QLineEdit):
|
||||
def __init__(self, theme, parent=None):
|
||||
QtGui.QLineEdit.__init__(self, parent)
|
||||
self.setStyleSheet(theme["convo/input/style"])
|
||||
def changeTheme(self, theme):
|
||||
self.setStyleSheet(theme["convo/input/style"])
|
||||
def focusInEvent(self, event):
|
||||
self.parent().clearNewMessage()
|
||||
QtGui.QLineEdit.focusInEvent(self, event)
|
||||
|
||||
class PesterConvo(QtGui.QFrame):
|
||||
def __init__(self, chum, initiated, mainwindow, parent=None):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
self.setFocusPolicy(QtCore.Qt.ClickFocus)
|
||||
self.chum = chum
|
||||
self.mainwindow = mainwindow
|
||||
convo = self.mainwindow.theme["convo"]
|
||||
self.resize(*convo["size"])
|
||||
self.setStyleSheet(convo["style"])
|
||||
self.setWindowIcon(chum.mood.icon(self.mainwindow.theme))
|
||||
self.setWindowTitle(chum.handle)
|
||||
|
||||
t = Template(self.mainwindow.theme["convo/chumlabel/text"])
|
||||
|
||||
self.chumLabel = QtGui.QLabel(t.safe_substitute(handle=chum.handle), self)
|
||||
self.chumLabel.setStyleSheet(self.mainwindow.theme["convo/chumlabel/style"])
|
||||
self.chumLabel.setAlignment(self.aligndict["h"][self.mainwindow.theme["convo/chumlabel/align/h"]] | self.aligndict["v"][self.mainwindow.theme["convo/chumlabel/align/v"]])
|
||||
self.chumLabel.setMaximumHeight(self.mainwindow.theme["convo/chumlabel/maxheight"])
|
||||
self.chumLabel.setMinimumHeight(self.mainwindow.theme["convo/chumlabel/minheight"])
|
||||
self.chumLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding))
|
||||
self.textArea = PesterText(self.mainwindow.theme, self)
|
||||
self.textInput = PesterInput(self.mainwindow.theme, self)
|
||||
self.textInput.setFocus()
|
||||
|
||||
self.connect(self.textInput, QtCore.SIGNAL('returnPressed()'),
|
||||
self, QtCore.SLOT('sentMessage()'))
|
||||
|
||||
self.layout = QtGui.QVBoxLayout()
|
||||
self.layout.addWidget(self.chumLabel)
|
||||
self.layout.addWidget(self.textArea)
|
||||
self.layout.addWidget(self.textInput)
|
||||
self.layout.setSpacing(0)
|
||||
self.layout.setMargin(0)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.chumopen = False
|
||||
|
||||
if parent:
|
||||
parent.addChat(self)
|
||||
if initiated:
|
||||
msg = self.mainwindow.profile().pestermsg(self.chum, QtGui.QColor(self.mainwindow.theme["convo/systemMsgColor"]), self.mainwindow.theme["convo/text/beganpester"])
|
||||
self.setChumOpen(True)
|
||||
self.textArea.append(convertTags(msg))
|
||||
self.mainwindow.chatlog.log(self.chum.handle, convertTags(msg, "bbcode"))
|
||||
self.newmessage = False
|
||||
|
||||
def updateMood(self, mood, unblocked=False):
|
||||
if mood.name() == "offline" and self.chumopen == True and not unblocked:
|
||||
msg = self.chum.pestermsg(self.mainwindow.profile(), QtGui.QColor(self.mainwindow.theme["convo/systemMsgColor"]), self.mainwindow.theme["convo/text/ceasepester"])
|
||||
self.textArea.append(convertTags(msg))
|
||||
self.mainwindow.chatlog.log(self.chum.handle, convertTags(msg, "bbcode"))
|
||||
self.chumopen = False
|
||||
if self.parent():
|
||||
self.parent().updateMood(self.chum.handle, mood, unblocked)
|
||||
else:
|
||||
if self.chum.blocked(self.mainwindow.config) and not unblocked:
|
||||
self.setWindowIcon(QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"]))
|
||||
else:
|
||||
self.setWindowIcon(mood.icon(self.mainwindow.theme))
|
||||
# print mood update?
|
||||
def updateBlocked(self):
|
||||
if self.parent():
|
||||
self.parent().updateBlocked(self.chum.handle)
|
||||
else:
|
||||
self.setWindowIcon(QtGui.QIcon(self.mainwindow.theme["main/chums/moods/blocked/icon"]))
|
||||
def updateColor(self, color):
|
||||
self.chum.color = color
|
||||
def addMessage(self, text, me=True):
|
||||
if me:
|
||||
chum = self.mainwindow.profile()
|
||||
else:
|
||||
chum = self.chum
|
||||
self.notifyNewMessage()
|
||||
self.textArea.addMessage(text, chum)
|
||||
|
||||
def notifyNewMessage(self):
|
||||
# first see if this conversation HASS the focus
|
||||
if not (self.hasFocus() or self.textArea.hasFocus() or
|
||||
self.textInput.hasFocus() or
|
||||
(self.parent() and self.parent().convoHasFocus(self.chum.handle))):
|
||||
# ok if it has a tabconvo parent, send that the notify.
|
||||
if self.parent():
|
||||
self.parent().notifyNewMessage(self.chum.handle)
|
||||
# if not change the window title and update system tray
|
||||
else:
|
||||
self.newmessage = True
|
||||
self.setWindowTitle(self.chum.handle+"*")
|
||||
def func():
|
||||
self.showChat()
|
||||
self.mainwindow.waitingMessages.addMessage(self.chum.handle, func)
|
||||
|
||||
def clearNewMessage(self):
|
||||
if self.parent():
|
||||
self.parent().clearNewMessage(self.chum.handle)
|
||||
elif self.newmessage:
|
||||
self.newmessage = False
|
||||
self.setWindowTitle(self.chum.handle)
|
||||
self.mainwindow.waitingMessages.messageAnswered(self.chum.handle)
|
||||
# reset system tray
|
||||
def focusInEvent(self, event):
|
||||
self.clearNewMessage()
|
||||
self.textInput.setFocus()
|
||||
def raiseChat(self):
|
||||
self.activateWindow()
|
||||
self.raise_()
|
||||
self.textInput.setFocus()
|
||||
|
||||
def showChat(self):
|
||||
if self.parent():
|
||||
self.parent().showChat(self.chum.handle)
|
||||
self.raiseChat()
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.mainwindow.waitingMessages.messageAnswered(self.chum.handle)
|
||||
self.windowClosed.emit(self.chum.handle)
|
||||
def setChumOpen(self, o):
|
||||
self.chumopen = o
|
||||
def changeTheme(self, theme):
|
||||
self.resize(*theme["convo/size"])
|
||||
self.setStyleSheet(theme["convo/style"])
|
||||
self.setWindowIcon(self.chum.mood.icon(theme))
|
||||
t = Template(self.mainwindow.theme["convo/chumlabel/text"])
|
||||
self.chumLabel.setText(t.safe_substitute(handle=self.chum.handle))
|
||||
self.chumLabel.setStyleSheet(theme["convo/chumlabel/style"])
|
||||
self.chumLabel.setAlignment(self.aligndict["h"][self.mainwindow.theme["convo/chumlabel/align/h"]] | self.aligndict["v"][self.mainwindow.theme["convo/chumlabel/align/v"]])
|
||||
self.chumLabel.setMaximumHeight(self.mainwindow.theme["convo/chumlabel/maxheight"])
|
||||
self.chumLabel.setMinimumHeight(self.mainwindow.theme["convo/chumlabel/minheight"])
|
||||
self.chumLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding))
|
||||
self.textArea.changeTheme(theme)
|
||||
self.textInput.changeTheme(theme)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def sentMessage(self):
|
||||
text = self.textInput.text()
|
||||
if text == "":
|
||||
return
|
||||
# deal with quirks here
|
||||
qtext = self.mainwindow.userprofile.quirks.apply(unicode(text))
|
||||
text = QtCore.QString(qtext)
|
||||
self.textInput.setText("")
|
||||
self.addMessage(text, True)
|
||||
# if ceased, rebegin
|
||||
if not self.chumopen:
|
||||
self.mainwindow.newConvoStarted.emit(QtCore.QString(self.chum.handle), True)
|
||||
# convert color tags
|
||||
text = convertTags(unicode(text), "ctag")
|
||||
self.messageSent.emit(text, self.chum)
|
||||
|
||||
messageSent = QtCore.pyqtSignal(QtCore.QString, PesterProfile)
|
||||
windowClosed = QtCore.pyqtSignal(QtCore.QString)
|
||||
|
||||
aligndict = {"h": {"center": QtCore.Qt.AlignHCenter,
|
||||
"left": QtCore.Qt.AlignLeft,
|
||||
"right": QtCore.Qt.AlignRight },
|
||||
"v": {"center": QtCore.Qt.AlignVCenter,
|
||||
"top": QtCore.Qt.AlignTop,
|
||||
"bottom": QtCore.Qt.AlignBottom } }
|
||||
|
||||
class PesterWindow(MovingWindow):
|
||||
def __init__(self, parent=None):
|
||||
|
@ -1076,6 +581,7 @@ class PesterWindow(MovingWindow):
|
|||
QtCore.Qt.FramelessWindowHint))
|
||||
|
||||
self.convos = {}
|
||||
self.memos = {}
|
||||
self.tabconvo = None
|
||||
|
||||
self.setObjectName("main")
|
||||
|
@ -1103,11 +609,16 @@ class PesterWindow(MovingWindow):
|
|||
self.userlistaction = userlistaction
|
||||
self.connect(userlistaction, QtCore.SIGNAL('triggered()'),
|
||||
self, QtCore.SLOT('showAllUsers()'))
|
||||
memoaction = QtGui.QAction(self.theme["main/menus/client/memos"], self)
|
||||
self.memoaction = memoaction
|
||||
self.connect(memoaction, QtCore.SIGNAL('triggered()'),
|
||||
self, QtCore.SLOT('showMemos()'))
|
||||
self.menu = QtGui.QMenuBar(self)
|
||||
|
||||
filemenu = self.menu.addMenu(self.theme["main/menus/client/_name"])
|
||||
self.filemenu = filemenu
|
||||
filemenu.addAction(opts)
|
||||
filemenu.addAction(memoaction)
|
||||
filemenu.addAction(userlistaction)
|
||||
filemenu.addAction(exitaction)
|
||||
|
||||
|
@ -1268,6 +779,27 @@ class PesterWindow(MovingWindow):
|
|||
self.connect(self.tabconvo, QtCore.SIGNAL('windowClosed()'),
|
||||
self, QtCore.SLOT('tabsClosed()'))
|
||||
|
||||
|
||||
def newMemo(self, channel):
|
||||
if self.memos.has_key(channel):
|
||||
# load memo
|
||||
return
|
||||
else:
|
||||
# do slider dialog then set
|
||||
if self.config.tabs():
|
||||
# create new tabbed memo window
|
||||
pass
|
||||
else:
|
||||
self.memoWindow = PesterMemo(channel, self, None)
|
||||
# connect signals
|
||||
# chat client send memo open
|
||||
self.memoWindow.show()
|
||||
|
||||
def addChum(self, chum):
|
||||
self.chumList.addChum(chum)
|
||||
self.config.addChum(chum)
|
||||
self.moodRequest.emit(chum)
|
||||
|
||||
def changeProfile(self, collision=None):
|
||||
if not hasattr(self, 'chooseprofile'):
|
||||
self.chooseprofile = None
|
||||
|
@ -1348,13 +880,7 @@ class PesterWindow(MovingWindow):
|
|||
if not pygame.mixer:
|
||||
self.alarm = NoneSound()
|
||||
else:
|
||||
self.alarm = pygame.mixer.Sound(theme["main/sounds/alertsound"]
|
||||
)
|
||||
|
||||
def addChum(self, chum):
|
||||
self.chumList.addChum(chum)
|
||||
self.config.addChum(chum)
|
||||
self.moodRequest.emit(chum)
|
||||
self.alarm = pygame.mixer.Sound(theme["main/sounds/alertsound"])
|
||||
|
||||
def changeTheme(self, theme):
|
||||
self.theme = theme
|
||||
|
@ -1393,6 +919,7 @@ class PesterWindow(MovingWindow):
|
|||
else:
|
||||
self.waitingMessages.answerMessage()
|
||||
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def blockSelectedChum(self):
|
||||
curChumListing = self.chumList.currentItem()
|
||||
|
@ -1539,6 +1066,39 @@ class PesterWindow(MovingWindow):
|
|||
self.unblockedChum.emit(handle)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def showMemos(self):
|
||||
if not hasattr(self, 'memochooser'):
|
||||
self.memochooser = None
|
||||
if self.memochooser:
|
||||
return
|
||||
self.memochooser = PesterMemoList(self)
|
||||
self.connect(self.memochooser, QtCore.SIGNAL('accepted()'),
|
||||
self, QtCore.SLOT('joinSelectedMemo()'))
|
||||
self.connect(self.memochooser, QtCore.SIGNAL('rejected()'),
|
||||
self, QtCore.SLOT('memoChooserClose()'))
|
||||
self.requestChannelList.emit()
|
||||
self.memochooser.show()
|
||||
@QtCore.pyqtSlot()
|
||||
def joinSelectedMemo(self):
|
||||
newmemo = self.memochooser.newmemoname()
|
||||
selectedmemo = self.memochooser.selectedmemo()
|
||||
if newmemo:
|
||||
self.newMemo('#'+newmemo)
|
||||
else:
|
||||
self.newMemo('#'+selectedmemo.text())
|
||||
self.memochooser = None
|
||||
@QtCore.pyqtSlot()
|
||||
def memoChooserClose(self):
|
||||
self.memochooser = None
|
||||
@QtCore.pyqtSlot()
|
||||
def memoChooserClose(self):
|
||||
self.memochooser = None
|
||||
|
||||
@QtCore.pyqtSlot(PesterList)
|
||||
def updateChannelList(self, channels):
|
||||
if hasattr(self, 'memochooser') and self.memochooser:
|
||||
self.memochooser.updateChannels(channels)
|
||||
@QtCore.pyqtSlot()
|
||||
def showAllUsers(self):
|
||||
if not hasattr(self, 'allusers'):
|
||||
self.allusers = None
|
||||
|
@ -1561,6 +1121,7 @@ class PesterWindow(MovingWindow):
|
|||
@QtCore.pyqtSlot()
|
||||
def userListClose(self):
|
||||
self.allusers = None
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def openQuirks(self):
|
||||
if not hasattr(self, 'quirkmenu'):
|
||||
|
@ -1705,6 +1266,8 @@ class PesterWindow(MovingWindow):
|
|||
return
|
||||
self.colorDialog = QtGui.QColorDialog(self)
|
||||
color = self.colorDialog.getColor(initial=self.profile().color)
|
||||
if not color.isValid():
|
||||
color = self.profile().color
|
||||
self.mychumcolor.setStyleSheet("background: %s" % color.name())
|
||||
self.userprofile.setColor(color)
|
||||
self.mycolorUpdated.emit()
|
||||
|
@ -1753,6 +1316,7 @@ class PesterWindow(MovingWindow):
|
|||
moodRequest = QtCore.pyqtSignal(PesterProfile)
|
||||
moodsRequest = QtCore.pyqtSignal(PesterList)
|
||||
moodUpdated = QtCore.pyqtSignal()
|
||||
requestChannelList = QtCore.pyqtSignal()
|
||||
requestNames = QtCore.pyqtSignal(QtCore.QString)
|
||||
namesUpdated = QtCore.pyqtSignal()
|
||||
userPresentSignal = QtCore.pyqtSignal(QtCore.QString,QtCore.QString,QtCore.QString)
|
||||
|
@ -1820,6 +1384,9 @@ class PesterIRC(QtCore.QObject):
|
|||
def requestNames(self, channel):
|
||||
c = unicode(channel)
|
||||
helpers.names(self.cli, c)
|
||||
@QtCore.pyqtSlot()
|
||||
def requestChannelList(self):
|
||||
helpers.channel_list(self.cli)
|
||||
|
||||
def updateIRC(self):
|
||||
self.conn.next()
|
||||
|
@ -1828,6 +1395,7 @@ class PesterIRC(QtCore.QObject):
|
|||
colorUpdated = QtCore.pyqtSignal(QtCore.QString, QtGui.QColor)
|
||||
messageReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
|
||||
namesReceived = QtCore.pyqtSignal(QtCore.QString, PesterList)
|
||||
channelListReceived = QtCore.pyqtSignal(PesterList)
|
||||
nickCollision = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
|
||||
userPresentUpdate = QtCore.pyqtSignal(QtCore.QString, QtCore.QString,
|
||||
QtCore.QString)
|
||||
|
@ -1918,7 +1486,20 @@ class PesterHandler(DefaultCommandHandler):
|
|||
pl = PesterList(namelist)
|
||||
del self.channelnames[channel]
|
||||
self.parent.namesReceived.emit(channel, pl)
|
||||
|
||||
|
||||
def liststart(self, server, handle, *info):
|
||||
self.channel_list = []
|
||||
info = list(info)
|
||||
self.channel_field = info.index("Channel") # dunno if this is protocol
|
||||
def list(self, server, handle, *info):
|
||||
channel = info[self.channel_field]
|
||||
if channel not in self.channel_list and channel != "#pesterchum":
|
||||
self.channel_list.append(channel)
|
||||
def listend(self, server, handle, msg):
|
||||
pl = PesterList(self.channel_list)
|
||||
self.parent.channelListReceived.emit(pl)
|
||||
self.channel_list = []
|
||||
|
||||
def getMood(self, *chums):
|
||||
chumglub = "GETMOOD "
|
||||
for c in chums:
|
||||
|
@ -2020,6 +1601,10 @@ def main():
|
|||
QtCore.SIGNAL('requestNames(QString)'),
|
||||
irc,
|
||||
QtCore.SLOT('requestNames(QString)'))
|
||||
irc.connect(widget,
|
||||
QtCore.SIGNAL('requestChannelList()'),
|
||||
irc,
|
||||
QtCore.SLOT('requestChannelList()'))
|
||||
|
||||
# IRC --> Main window
|
||||
irc.connect(irc,
|
||||
|
@ -2046,6 +1631,10 @@ def main():
|
|||
QtCore.SIGNAL('userPresentUpdate(QString, QString, QString)'),
|
||||
widget,
|
||||
QtCore.SLOT('userPresentUpdate(QString, QString, QString)'))
|
||||
irc.connect(irc,
|
||||
QtCore.SIGNAL('channelListReceived(PyQt_PyObject)'),
|
||||
widget,
|
||||
QtCore.SLOT('updateChannelList(PyQt_PyObject)'))
|
||||
|
||||
ircapp = IRCThread(irc)
|
||||
ircapp.start()
|
||||
|
|
BIN
pesterdata.pyc
BIN
pesterdata.pyc
Binary file not shown.
BIN
pestermenus.pyc
BIN
pestermenus.pyc
Binary file not shown.
|
@ -1 +1 @@
|
|||
{"color": "#aa00ff", "theme": "trollian", "quirks": [], "handle": "testProfile"}
|
||||
{"color": "#aa00ff", "theme": "pesterchum", "quirks": [], "handle": "testProfile"}
|
174
setup-py2exe.py
Normal file
174
setup-py2exe.py
Normal file
|
@ -0,0 +1,174 @@
|
|||
# ======================================================#
|
||||
# File automagically generated by GUI2Exe version 0.3
|
||||
# Andrea Gavana, 01 April 2007
|
||||
# ======================================================#
|
||||
|
||||
# Let's start with some default (for me) imports...
|
||||
|
||||
from distutils.core import setup
|
||||
import py2exe
|
||||
import glob
|
||||
import os
|
||||
import zlib
|
||||
import shutil
|
||||
|
||||
# Remove the build folder
|
||||
shutil.rmtree("build", ignore_errors=True)
|
||||
|
||||
# do the same for dist folder
|
||||
shutil.rmtree("dist", ignore_errors=True)
|
||||
|
||||
MANIFEST_TEMPLATE = """
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
version="5.0.0.0"
|
||||
processorArchitecture="x86"
|
||||
name="%(prog)s"
|
||||
type="win32"
|
||||
/>
|
||||
<description>%(prog)s</description>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel
|
||||
level="asInvoker"
|
||||
uiAccess="false">
|
||||
</requestedExecutionLevel>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.VC90.CRT"
|
||||
version="9.0.21022.8"
|
||||
processorArchitecture="x86"
|
||||
publicKeyToken="1fc8b3b9a1e18e3b">
|
||||
</assemblyIdentity>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="X86"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
||||
"""
|
||||
|
||||
class Target(object):
|
||||
""" A simple class that holds information on our executable file. """
|
||||
def __init__(self, **kw):
|
||||
""" Default class constructor. Update as you need. """
|
||||
self.__dict__.update(kw)
|
||||
|
||||
|
||||
# Ok, let's explain why I am doing that.
|
||||
# Often, data_files, excludes and dll_excludes (but also resources)
|
||||
# can be very long list of things, and this will clutter too much
|
||||
# the setup call at the end of this file. So, I put all the big lists
|
||||
# here and I wrap them using the textwrap module.
|
||||
|
||||
data_files = []
|
||||
|
||||
includes = []
|
||||
excludes = ['_gtkagg', '_tkagg', 'bsddb', 'curses', 'email', 'pywin.debugger',
|
||||
'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl',
|
||||
'Tkconstants', 'Tkinter']
|
||||
packages = []
|
||||
dll_excludes = ['libgdk-win32-2.0-0.dll', 'libgobject-2.0-0.dll', 'tcl84.dll',
|
||||
'tk84.dll',
|
||||
'MSVCP90.dll', 'mswsock.dll', 'powrprof.dll']
|
||||
icon_resources = []
|
||||
bitmap_resources = []
|
||||
other_resources = []
|
||||
other_resources = [(24, 1, MANIFEST_TEMPLATE % dict(prog="MyAppName"))]
|
||||
|
||||
|
||||
# This is a place where the user custom code may go. You can do almost
|
||||
# whatever you want, even modify the data_files, includes and friends
|
||||
# here as long as they have the same variable name that the setup call
|
||||
# below is expecting.
|
||||
|
||||
|
||||
#
|
||||
# The following will copy the MSVC run time dll's
|
||||
# (msvcm90.dll, msvcp90.dll and msvcr90.dll) and
|
||||
# the Microsoft.VC90.CRT.manifest which I keep in the
|
||||
# "Py26MSdlls" folder to the dist folder
|
||||
#
|
||||
# depending on wx widgets you use, you might need to add
|
||||
# gdiplus.dll to the above collection
|
||||
|
||||
py26MSdll = glob.glob(r"c:\Dev\Py26MSdlls-9.0.21022.8\msvc\*.*")
|
||||
|
||||
# install the MSVC 9 runtime dll's into the application folder
|
||||
data_files += [("", py26MSdll),]
|
||||
|
||||
# I found on some systems one has to put them into sub-folders.
|
||||
##data_files += [("Microsoft.VC90.CRT", py26MSdll),
|
||||
## ("lib\Microsoft.VC90.CRT", py26MSdll)]
|
||||
|
||||
|
||||
|
||||
# Ok, now we are going to build our target class.
|
||||
# I chose this building strategy as it works perfectly for me :-D
|
||||
|
||||
|
||||
GUI2Exe_Target_1 = Target(
|
||||
# what to build
|
||||
script = "test.py",
|
||||
icon_resources = icon_resources,
|
||||
bitmap_resources = bitmap_resources,
|
||||
other_resources = other_resources,
|
||||
dest_base = "test",
|
||||
version = "0.1",
|
||||
company_name = "No Company",
|
||||
copyright = "No Copyrights",
|
||||
name = "Py2Exe Sample File"
|
||||
)
|
||||
|
||||
|
||||
|
||||
# That's serious now: we have all (or almost all) the options py2exe
|
||||
# supports. I put them all even if some of them are usually defaulted
|
||||
# and not used. Some of them I didn't even know about.
|
||||
|
||||
setup(
|
||||
|
||||
data_files = data_files,
|
||||
|
||||
options = {"py2exe": {"compressed": 2,
|
||||
"optimize": 2,
|
||||
"includes": includes,
|
||||
"excludes": excludes,
|
||||
"packages": packages,
|
||||
"dll_excludes": dll_excludes,
|
||||
"bundle_files": 2,
|
||||
"dist_dir": "dist",
|
||||
"xref": False,
|
||||
"skip_archive": False,
|
||||
"ascii": False,
|
||||
"custom_boot_script": '',
|
||||
}
|
||||
},
|
||||
|
||||
zipfile = "lib\library.zip",
|
||||
console = [],
|
||||
windows = [GUI2Exe_Target_1]
|
||||
)
|
||||
|
||||
# This is a place where any post-compile code may go.
|
||||
# You can add as much code as you want, which can be used, for example,
|
||||
# to clean up your folders or to do some particular post-compilation
|
||||
# actions.
|
||||
|
||||
# And we are done. That's a setup script :-D
|
32
setup.py
Normal file
32
setup.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
from cx_Freeze import setup, Executable
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
|
||||
if sys.platform == "win32":
|
||||
base = "Win32GUI"
|
||||
else:
|
||||
base = "Console"
|
||||
|
||||
setup(
|
||||
name = "P3ST3RCHUM",
|
||||
version = "3.14",
|
||||
description = "P3ST3RCHUM",
|
||||
executables = [Executable("pesterchum.py",
|
||||
base=base,
|
||||
icon="pesterchum.ico",
|
||||
compress=True,
|
||||
)])
|
||||
if sys.platform == "win32":
|
||||
os.rename("build/exe.win32-2.6", "build/pesterchum")
|
||||
|
||||
shutil.copytree("themes", "build/pesterchum/themes")
|
||||
shutil.copytree("imageformats", "build/pesterchum/imageformats")
|
||||
shutil.copy("pesterchum.js", "build/pesterchum/")
|
||||
shutil.copy("C:/Dev/Py26MSdlls-9.0.21022.8/msvc/msvcm90.dll", "build/pesterchum")
|
||||
shutil.copy("C:/Dev/Py26MSdlls-9.0.21022.8/msvc/msvcp90.dll", "build/pesterchum")
|
||||
shutil.copy("C:/Dev/Py26MSdlls-9.0.21022.8/msvc/msvcr90.dll", "build/pesterchum")
|
||||
shutil.copy("C:/Dev/Py26MSdlls-9.0.21022.8/msvc/x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8_x-ww_d08d0375.manifest",
|
||||
"build/pesterchum")
|
||||
os.mkdir("build/pesterchum/profiles")
|
||||
os.mkdir("build/pesterchum/logs")
|
BIN
themes/pesterchum/memo.png
Normal file
BIN
themes/pesterchum/memo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 265 B |
|
@ -17,6 +17,7 @@
|
|||
"sounds": { "alertsound": "$path/alarm.wav" },
|
||||
"menus": {"client": {"_name": "CLIENT",
|
||||
"options": "OPTIONS",
|
||||
"memos": "MEMOS",
|
||||
"userlist": "USERLIST",
|
||||
"exit": "EXIT"},
|
||||
"profile": {"_name": "PROFILE",
|
||||
|
@ -183,6 +184,7 @@
|
|||
},
|
||||
"convo":
|
||||
{"style": "background: #fdb302; border:2px solid yellow; font-family: 'Courier'",
|
||||
"margins": {"top": 0, "bottom": 0, "left": 0, "right": 0 },
|
||||
"size": [295, 191],
|
||||
"chumlabel": { "style": "background: rgb(196, 138, 0); color: white; border:0px;",
|
||||
"align": { "h": "center", "v": "center" },
|
||||
|
@ -209,6 +211,25 @@
|
|||
"unblocked": "unblocked"
|
||||
},
|
||||
"systemMsgColor": "#646464"
|
||||
},
|
||||
"memos":
|
||||
{"memoicon": "$path/memo.png",
|
||||
"style": "background: #fdb302; font-family:'Courier';font:bold;selection-background-color:#919191; ",
|
||||
"size": [600,300],
|
||||
"label": { "text": "$channel",
|
||||
"style": "background: rgb(196, 138, 0); color: white; border:0px;",
|
||||
"align": { "h": "center", "v": "center" },
|
||||
"minheight": 30,
|
||||
"maxheight": 50
|
||||
},
|
||||
"input": { "style": "background: white; border:2px solid #c48a00;margin-top:5px;" },
|
||||
"textarea": { "style": "background: white; font:bold; border:2px solid #c48a00;text-align:center;" },
|
||||
"margins": {"top": 0, "bottom": 0, "left": 0, "right": 0 },
|
||||
"userlist": { "width": 150 },
|
||||
"time": { "text": { "width": 75, "style": "" },
|
||||
"slider": { "style": "",
|
||||
"groove": "",
|
||||
"handle": "" }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
BIN
themes/trollian/memo.png
Normal file
BIN
themes/trollian/memo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 265 B |
|
@ -10,13 +10,14 @@
|
|||
"loc": [621, 8]},
|
||||
"menubar": { "style": "font-family: 'Arial'; font-size: 11px; color: rgba(0,0,0,0);" },
|
||||
"menu" : { "style": "font-family: 'Arial'; font-size: 11px; background-color: #c2c2c2; border:1px solid #545454;",
|
||||
"selected": "background-color: #545454",
|
||||
"menuitem": "margin-right:14px;",
|
||||
"loc": [14,90]
|
||||
"selected": "background-color: #545454",
|
||||
"menuitem": "margin-right:14px;",
|
||||
"loc": [14,90]
|
||||
},
|
||||
"sounds": { "alertsound": "$path/alarm.wav" },
|
||||
"menus": {"client": {"_name": "Trollian",
|
||||
"options": "Options",
|
||||
"memos": "Memos",
|
||||
"userlist": "Fresh Targets",
|
||||
"exit": "Abscond"},
|
||||
"profile": {"_name": "View",
|
||||
|
@ -31,58 +32,58 @@
|
|||
"addchum": "Add Chump",
|
||||
"unblockchum": "Mercy"}
|
||||
},
|
||||
"chums": { "style": "border: 0px; background-color: white; padding: 5px; font-family: 'Arial';selection-background-color:rgb(200,200,200); ",
|
||||
"loc": [476, 90],
|
||||
"chums": { "style": "font-size: 12px; background: white; border:2px solid #c2c2c2; padding: 5px; font-family: 'Arial';selection-background-color:rgb(200,200,200); ",
|
||||
"loc": [475, 89],
|
||||
"size": [175, 361],
|
||||
"userlistcolor": "black",
|
||||
"moods": {
|
||||
|
||||
"chummy": { "icon": "$path/chummy.png", "color": "#63ea00" },
|
||||
|
||||
"rancorous": { "icon": "$path/rancorous.png", "color": "#7f7f7f" },
|
||||
|
||||
"offline": { "icon": "$path/offline.png", "color": "black"},
|
||||
|
||||
|
||||
"pleasant": { "icon": "$path/pleasant.png", "color": "#d69df8" },
|
||||
|
||||
"distraught": { "icon": "$path/distraught.png", "color": "#706eba" },
|
||||
|
||||
"unruly": { "icon": "$path/unruly.png", "color": "blue" },
|
||||
|
||||
|
||||
"smooth": { "icon": "$path/smooth.png", "color": "red" },
|
||||
|
||||
|
||||
"ecstatic": { "icon": "$path/ecstatic.png", "color": "#99004d" },
|
||||
|
||||
"relaxed": { "icon": "$path/relaxed.png", "color": "#078446" },
|
||||
|
||||
"discontent": { "icon": "$path/discontent.png", "color": "#a75403" },
|
||||
|
||||
"devious": { "icon": "$path/devious.png", "color": "#008282" },
|
||||
|
||||
"sleek": { "icon": "$path/sleek.png", "color": "#a1a100" },
|
||||
|
||||
"detestful": { "icon": "$path/detestful.png", "color": "#6a006a" },
|
||||
|
||||
"mirthful": { "icon": "$path/mirthful.png", "color": "#450077" },
|
||||
|
||||
"manipulative": { "icon": "$path/manipulative.png", "color": "#004182" },
|
||||
|
||||
"vigorous": { "icon": "$path/vigorous.png", "color": "#0021cb" },
|
||||
|
||||
"perky": { "icon": "$path/perky.png", "color": "#406600" },
|
||||
|
||||
"acceptant": { "icon": "$path/acceptant.png", "color": "#a10000" },
|
||||
|
||||
"protective": { "icon": "$path/protective.png", "color": "white" },
|
||||
|
||||
"blocked": { "icon": "$path/blocked.png", "color": "black" }
|
||||
|
||||
}
|
||||
"moods": {
|
||||
|
||||
"chummy": { "icon": "$path/chummy.png", "color": "#63ea00" },
|
||||
|
||||
"rancorous": { "icon": "$path/rancorous.png", "color": "#7f7f7f" },
|
||||
|
||||
"offline": { "icon": "$path/offline.png", "color": "black"},
|
||||
|
||||
|
||||
"pleasant": { "icon": "$path/pleasant.png", "color": "#d69df8" },
|
||||
|
||||
"distraught": { "icon": "$path/distraught.png", "color": "#706eba" },
|
||||
|
||||
"unruly": { "icon": "$path/unruly.png", "color": "blue" },
|
||||
|
||||
|
||||
"smooth": { "icon": "$path/smooth.png", "color": "red" },
|
||||
|
||||
|
||||
"ecstatic": { "icon": "$path/ecstatic.png", "color": "#99004d" },
|
||||
|
||||
"relaxed": { "icon": "$path/relaxed.png", "color": "#078446" },
|
||||
|
||||
"discontent": { "icon": "$path/discontent.png", "color": "#a75403" },
|
||||
|
||||
"devious": { "icon": "$path/devious.png", "color": "#008282" },
|
||||
|
||||
"sleek": { "icon": "$path/sleek.png", "color": "#a1a100" },
|
||||
|
||||
"detestful": { "icon": "$path/detestful.png", "color": "#6a006a" },
|
||||
|
||||
"mirthful": { "icon": "$path/mirthful.png", "color": "#450077" },
|
||||
|
||||
"manipulative": { "icon": "$path/manipulative.png", "color": "#004182" },
|
||||
|
||||
"vigorous": { "icon": "$path/vigorous.png", "color": "#0021cb" },
|
||||
|
||||
"perky": { "icon": "$path/perky.png", "color": "#406600" },
|
||||
|
||||
"acceptant": { "icon": "$path/acceptant.png", "color": "#a10000" },
|
||||
|
||||
"protective": { "icon": "$path/protective.png", "color": "white" },
|
||||
|
||||
"blocked": { "icon": "$path/blocked.png", "color": "black" }
|
||||
|
||||
}
|
||||
},
|
||||
"trollslum": {
|
||||
"trollslum": {
|
||||
"style": "background: rgb(190, 19, 4); font-family: 'Arial'",
|
||||
"size": [175, 461],
|
||||
"label": { "text": "Chumpdump",
|
||||
|
@ -99,7 +100,7 @@
|
|||
"size": [0,0],
|
||||
"text": "" }
|
||||
},
|
||||
"defaultwindow": { "style": "background: #c2c2c2; font-family:'Arial';font:bold;selection-background-color:#545454; "
|
||||
"defaultwindow": { "style": "background: #c2c2c2; font-family:'Arial';font:bold;selection-background-color:#545454; "
|
||||
},
|
||||
"addchum": { "style": "background: rgba(0,0,0,0); border:0px; color: rgba(0,0,0,0);",
|
||||
"loc": [475, 67],
|
||||
|
@ -107,142 +108,143 @@
|
|||
"text": ""
|
||||
},
|
||||
"pester": { "style": "background: rgba(0,0,0,0); border:0px; color: rgba(0,0,0,0);",
|
||||
"loc": [0,0],
|
||||
"size": [0, 0],
|
||||
"text": ""
|
||||
},
|
||||
"loc": [0,0],
|
||||
"size": [0, 0],
|
||||
"text": ""
|
||||
},
|
||||
"block": { "style": "background: rgba(0,0,0,0); border:0px; color: rgba(0,0,0,0);",
|
||||
"loc": [1500,202],
|
||||
"size": [71, 22],
|
||||
"text": ""
|
||||
},
|
||||
"loc": [1500,202],
|
||||
"size": [71, 22],
|
||||
"text": ""
|
||||
},
|
||||
"defaultmood": 7,
|
||||
"moodlabel": { "style": "",
|
||||
"loc": [0, 0],
|
||||
"text": ""
|
||||
},
|
||||
"loc": [0, 0],
|
||||
"text": ""
|
||||
},
|
||||
"moods": [
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck1.png); border:0px;",
|
||||
"loc": [25, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 17
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck2.png); border:0px;",
|
||||
"loc": [60, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 9
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck3.png); border:0px;",
|
||||
"loc": [95, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 11
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck4.png); border:0px;",
|
||||
"loc": [130, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 1
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck5.png); border:0px;",
|
||||
"loc": [165, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 16
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck6.png); border:0px;",
|
||||
"loc": [200, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 8
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck7.png); border:0px;",
|
||||
"loc": [235, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 10
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck8.png); border:0px;",
|
||||
"loc": [270, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 14
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck9.png); border:0px;",
|
||||
"loc": [305, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 15
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck10.png); border:0px;",
|
||||
"loc": [340, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 13
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck11.png); border:0px;",
|
||||
"loc": [375, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 12
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck12.png); border:0px;",
|
||||
"loc": [410, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 7
|
||||
},
|
||||
|
||||
{ "style": "border:0px;color: rgba(0, 0, 0, 0%);",
|
||||
"selected": "border:0px; color: rgba(0, 0, 0, 0%);",
|
||||
"loc": [12, 117],
|
||||
"size": [435, 18],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 2
|
||||
}
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck1.png); border:0px;",
|
||||
"loc": [25, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 17
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck2.png); border:0px;",
|
||||
"loc": [60, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 9
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck3.png); border:0px;",
|
||||
"loc": [95, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 11
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck4.png); border:0px;",
|
||||
"loc": [130, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 1
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck5.png); border:0px;",
|
||||
"loc": [165, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 16
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck6.png); border:0px;",
|
||||
"loc": [200, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 8
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck7.png); border:0px;",
|
||||
"loc": [235, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 10
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck8.png); border:0px;",
|
||||
"loc": [270, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 14
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck9.png); border:0px;",
|
||||
"loc": [305, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 15
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck10.png); border:0px;",
|
||||
"loc": [340, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 13
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck11.png); border:0px;",
|
||||
"loc": [375, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 12
|
||||
},
|
||||
{ "style": "border:0px;",
|
||||
"selected": "background-image:url($path/moodcheck12.png); border:0px;",
|
||||
"loc": [410, 141],
|
||||
"size": [20, 270],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 7
|
||||
},
|
||||
|
||||
{ "style": "border:0px;color: rgba(0, 0, 0, 0%);",
|
||||
"selected": "border:0px; color: rgba(0, 0, 0, 0%);",
|
||||
"loc": [12, 117],
|
||||
"size": [435, 18],
|
||||
"text": "",
|
||||
"icon": "",
|
||||
"mood": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"convo":
|
||||
{"style": "background: rgb(190, 19, 4); font-family: 'Arial';",
|
||||
"size": [308, 194],
|
||||
"chumlabel": { "style": "background: rgb(255, 38, 18); color: white;",
|
||||
"align": { "h": "center", "v": "center" },
|
||||
"minheight": 30,
|
||||
"maxheight": 50,
|
||||
"text" : "trolling: $handle"
|
||||
"margins": {"top": 22, "bottom": 9, "left": 10, "right": 4 },
|
||||
"size": [400, 250],
|
||||
"chumlabel": { "style": "background: rgb(255, 38, 18); color: white; padding: 2px; border:1px solid #c2c2c2;",
|
||||
"align": { "h": "left", "v": "center" },
|
||||
"minheight": 18,
|
||||
"maxheight": 18,
|
||||
"text" : "trolling: $handle"
|
||||
},
|
||||
"textarea": {
|
||||
"style": "background: white; border:0px;"
|
||||
"style": "background: white; border:2px solid #c2c2c2; font-size: 12px; margin-top: 4px;"
|
||||
},
|
||||
"input": {
|
||||
"style": "background: white; border:0px solid #c48a00;margin-top:5px;"
|
||||
"style": "background: white;margin-top:5px; border:1px solid #c2c2c2; margin-right: 54px; font-size: 12px;"
|
||||
},
|
||||
"tabs": {
|
||||
"style": "",
|
||||
|
@ -257,6 +259,10 @@
|
|||
"unblocked": "mercifully forgave"
|
||||
},
|
||||
"systemMsgColor": "#646464"
|
||||
}
|
||||
|
||||
},
|
||||
"memos":
|
||||
{"memoicon": "$path/memo.png"
|
||||
|
||||
}
|
||||
|
||||
}
|
18
tmp.py
Normal file
18
tmp.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
class PesterMemo(PesterConvo):
|
||||
def __init__()
|
||||
def updateMood: pass
|
||||
def updateBlocked
|
||||
def updateColor: pass
|
||||
def addMessage
|
||||
def notifyNewMessage
|
||||
def clearNewMessage
|
||||
def changeTheme
|
||||
|
||||
slot
|
||||
def sentMessage
|
||||
|
||||
messageSent - signal -> sendMessage -> sendMessage(Memo)
|
||||
windowClosed - signal -> closeMemo
|
||||
|
||||
self.textInput
|
||||
self.textArea
|
Loading…
Reference in a new issue